//-------------------------------------------------------------------------------------------------- void supCtrl_GetLabel ( const char* appName, ///< [IN] Application name. char* label, ///< [OUT] SMACK label for the application. size_t labelSize ///< [IN] Size of the SMACK label string. ) //-------------------------------------------------------------------------------------------------- { static bool connectedToSmack = false; if (!connectedToSmack) { appSmack_ConnectService(); connectedToSmack = true; } appSmack_GetLabel(appName, label, labelSize); }
//-------------------------------------------------------------------------------------------------- static inline le_result_t StartProc ( proc_Ref_t procRef, ///< [IN] The process to start. const char* workingDirPtr, ///< [IN] The path to the process's working directory, relative /// to the sandbox directory. uid_t uid, ///< [IN] The user ID to start the process as. gid_t gid, ///< [IN] The primary group ID for this process. const gid_t* groupsPtr, ///< [IN] List of supplementary groups for this process. size_t numGroups, ///< [IN] The number of groups in the supplementary groups list. const char* sandboxDirPtr ///< [IN] The path to the root of the sandbox this process is to /// run in. If NULL then process will be unsandboxed. ) { if (procRef->pid != -1) { LE_ERROR("Process '%s' (PID: %d) cannot be started because it is already running.", procRef->name, procRef->pid); return LE_FAULT; } // Create a pipe for parent/child synchronization. int syncPipeFd[2]; LE_FATAL_IF(pipe(syncPipeFd) == -1, "Could not create synchronization pipe. %m."); // @Note The current IPC system does not support forking so any reads to the config DB must be // done in the parent process. // Get the environment variables from the config tree for this process. EnvVar_t envVars[LIMIT_MAX_NUM_ENV_VARS]; int numEnvVars = GetEnvironmentVariables(procRef, envVars, LIMIT_MAX_NUM_ENV_VARS); if (numEnvVars == LE_FAULT) { LE_ERROR("Error getting environment variables. Process '%s' cannot be started.", procRef->name); return LE_FAULT; } // Get the command line arguments from the config tree for this process. char argsBuffers[LIMIT_MAX_NUM_CMD_LINE_ARGS][LIMIT_MAX_ARGS_STR_BYTES]; char* argsPtr[NUM_ARGS_PTRS]; if (GetArgs(procRef, argsBuffers, argsPtr) != LE_OK) { LE_ERROR("Could not get command line arguments, process '%s' cannot be started.", procRef->name); return LE_FAULT; } // Get the smack label for the process. // Must get the label here because smack_GetAppLabel uses the config and we can not // use any IPC after a fork. char smackLabel[LIMIT_MAX_SMACK_LABEL_BYTES]; appSmack_GetLabel(app_GetName(procRef->appRef), smackLabel, sizeof(smackLabel)); // Create pipes for the process's standard error and standard out streams. int stderrPipe[2]; int stdoutPipe[2]; CreatePipe(procRef, stderrPipe, STDERR_FILENO); CreatePipe(procRef, stdoutPipe, STDOUT_FILENO); // Create the child process pid_t pID = fork(); if (pID < 0) { LE_EMERG("Failed to fork. %m."); return LE_FAULT; } if (pID == 0) { // Wait for the parent to allow us to continue by blocking on the read pipe until it // is closed. fd_Close(syncPipeFd[WRITE_PIPE]); ssize_t numBytesRead; int dummyBuf; do { numBytesRead = read(syncPipeFd[READ_PIPE], &dummyBuf, 1); } while ( ((numBytesRead == -1) && (errno == EINTR)) || (numBytesRead != 0) ); LE_FATAL_IF(numBytesRead == -1, "Could not read synchronization pipe. %m."); // The parent has allowed us to continue. // Redirect the process's standard streams. RedirectStdStream(stderrPipe, STDERR_FILENO); RedirectStdStream(stdoutPipe, STDOUT_FILENO); // Set the process's SMACK label. smack_SetMyLabel(smackLabel); // Set the umask so that files are not accidentally created with global permissions. umask(S_IRWXG | S_IRWXO); // Unblock all signals that might have been blocked. sigset_t sigSet; LE_ASSERT(sigfillset(&sigSet) == 0); LE_ASSERT(pthread_sigmask(SIG_UNBLOCK, &sigSet, NULL) == 0); SetEnvironmentVariables(envVars, numEnvVars); // Setup the process environment. if (sandboxDirPtr != NULL) { // Sandbox the process. sandbox_ConfineProc(sandboxDirPtr, uid, gid, groupsPtr, numGroups, workingDirPtr); } else { ConfigNonSandboxedProcess(workingDirPtr); } // Launch the child program. This should not return unless there was an error. LE_INFO("Execing '%s'", argsPtr[0]); // Close all non-standard file descriptors. fd_CloseAllNonStd(); execvp(argsPtr[0], &(argsPtr[1])); // The program could not be started. Log an error message. log_ReInit(); LE_FATAL("Could not exec '%s'. %m.", argsPtr[0]); } procRef->pid = pID; procRef->paused = false; // Don't need this end of the pipe. fd_Close(syncPipeFd[READ_PIPE]); // Set the scheduling priority for the child process while the child process is blocked. SetSchedulingPriority(procRef); // Send standard pipes to the log daemon so they will show up in the logs. SendStdPipeToLogDaemon(procRef, stderrPipe, STDERR_FILENO); SendStdPipeToLogDaemon(procRef, stdoutPipe, STDOUT_FILENO); // Set the resource limits for the child process while the child process is blocked. if (resLim_SetProcLimits(procRef) != LE_OK) { LE_ERROR("Could not set the resource limits. %m."); kill_Hard(procRef->pid); } LE_INFO("Starting process %s with pid %d", procRef->name, procRef->pid); // Unblock the child process. fd_Close(syncPipeFd[WRITE_PIPE]); return LE_OK; }