| // Copyright 2012 The ChromiumOS Authors | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file. | |
| #ifndef LIBBRILLO_BRILLO_PROCESS_PROCESS_H_ | |
| #define LIBBRILLO_BRILLO_PROCESS_PROCESS_H_ | |
| #include <sys/types.h> | |
| #include <map> | |
| #include <string> | |
| #include <vector> | |
| #include <base/files/file_path.h> | |
| #include <base/functional/bind.h> | |
| #include <base/functional/callback.h> | |
| #include <base/strings/string_util.h> | |
| #include <base/strings/stringprintf.h> | |
| #include <brillo/brillo_export.h> | |
| #include <gtest/gtest_prod.h> | |
| namespace brillo { | |
| // Manages a process. Can create the process, attach to an existing | |
| // process by pid or pid file, and kill the process. Upon destruction | |
| // any managed process is killed with SIGKILL. Use Release() to | |
| // release the process from management. A given system process may | |
| // only be managed by one Process at a time. | |
| class BRILLO_EXPORT Process { | |
| public: | |
| Process(); | |
| virtual ~Process(); | |
| // Adds |arg| to the executable command-line to be run. The | |
| // executable name itself is the first argument. | |
| virtual void AddArg(const std::string& arg) = 0; | |
| // Adds |option| and |value| as an option with a string value to the | |
| // command line to be run. | |
| inline void AddStringOption(const std::string& option, | |
| const std::string& value) { | |
| AddArg(option); | |
| AddArg(value); | |
| } | |
| // Adds |option| and |value| as an option which takes an integer | |
| // value to the command line to be run. | |
| inline void AddIntOption(const std::string& option, int value) { | |
| AddArg(option); | |
| AddArg(base::StringPrintf("%d", value)); | |
| } | |
| // Redirects |child_fd| to /dev/null. | |
| virtual void RedirectDevNull(int child_fd) = 0; | |
| // Redirects to read stdin from |input_file|. |input_file| must not be | |
| // a symlink. | |
| virtual void RedirectInput(const base::FilePath& input_file) = 0; | |
| virtual void RedirectInput(const std::string& input_file) = 0; | |
| // Redirects stderr and stdout to |output_file|. |output_file| must not be | |
| // a symlink. | |
| virtual void RedirectOutput(const base::FilePath& output_file) = 0; | |
| virtual void RedirectOutput(const std::string& output_file) = 0; | |
| // Redirect stderr and stdout to memfd, use |combine| to combine stderr and | |
| // stdout. | |
| virtual void RedirectOutputToMemory(bool combine) = 0; | |
| // Indicates we want to redirect |child_fd| in the child process's | |
| // file table to |output_file|. | |
| virtual void RedirectUsingFile(int child_fd, | |
| const base::FilePath& output_file) = 0; | |
| // Indicates we want to redirect |child_fd| in the child process's | |
| // file table to a memfd. | |
| virtual void RedirectUsingMemory(int child_fd) = 0; | |
| // Indicates we want to redirect |child_fd| in the child process's | |
| // file table to a pipe. |child_fd| will be available for reading | |
| // from child process's perspective iff |is_input|. | |
| virtual void RedirectUsingPipe(int child_fd, bool is_input) = 0; | |
| // Binds the given file descriptor in the parent to the given file | |
| // descriptor in the child. | |
| virtual void BindFd(int parent_fd, int child_fd) = 0; | |
| // Set a flag |close_unused_fds| to indicate if the child process | |
| // should close all unused file descriptors inherited from the | |
| // parent process. This will not close the file descriptors for | |
| // the standard streams (stdin, stdout, and stderr). | |
| virtual void SetCloseUnusedFileDescriptors(bool close_unused_fds) = 0; | |
| // Set the real/effective/saved user ID of the child process. | |
| virtual void SetUid(uid_t uid) = 0; | |
| // Set the real/effective/saved group ID of the child process. | |
| virtual void SetGid(gid_t gid) = 0; | |
| // Set the process group ID of the child process. If the argument is 0, | |
| // then it will be set to the pid of the child process, which will be a | |
| // new group initially only containing itself. | |
| virtual void SetPgid(pid_t pgid) = 0; | |
| // Set the capabilities assigned to the child process. | |
| // NOTE: |capmask| is indeed a mask and should be passed in as the result of | |
| // the CAP_TO_MASK(capability) macro, e.g. | |
| // my_process.SetCapabilities(CAP_TO_MASK(CAP_SETUID) | | |
| // CAP_TO_MASK(CAP_SETGID)); | |
| // NOTE: supporting this sandboxing feature is optional (provide no-op | |
| // implementation if your Process implementation does not support this). | |
| virtual void SetCapabilities(uint64_t capmask) = 0; | |
| // Apply a syscall filter to the process using the policy file at |path|. | |
| // NOTE: supporting this sandboxing feature is optional (provide no-op | |
| // implementation if your Process implementation does not support this). | |
| virtual void ApplySyscallFilter(const base::FilePath& path) = 0; | |
| // Enter new PID namespace when this process is run. | |
| // NOTE: supporting this sandboxing feature is optional (provide no-op | |
| // implementation if your Process implementation does not support this). | |
| virtual void EnterNewPidNamespace() = 0; | |
| // Set a flag |inherit| to indicate if the child process intend to | |
| // inherit signal mask from the parent process. When |inherit| is | |
| // set to true, the child process will inherit signal mask from the | |
| // parent process. This could cause unintended side effect, where all | |
| // the signals to the child process might be blocked if they are set | |
| // in the parent's signal mask. | |
| virtual void SetInheritParentSignalMask(bool inherit) = 0; | |
| typedef base::OnceCallback<bool(void)> PreExecCallback; | |
| // Set the pre-exec callback. This is called after all setup is complete but | |
| // before we exec() the process. The callback may return false to cause Start | |
| // to return false without starting the process. | |
| virtual void SetPreExecCallback(PreExecCallback cb) = 0; | |
| // Sets whether starting the process should search the system path or not. | |
| // By default the system path will not be searched. | |
| virtual void SetSearchPath(bool search_path) = 0; | |
| // Gets the pipe file descriptor mapped to the process's |child_fd|. | |
| virtual int GetPipe(int child_fd) = 0; | |
| // Gets the contents of memfd for the |child_fd|. | |
| virtual std::string GetOutputString(int child_fd) = 0; | |
| // Gets the memfd for the |child_fd|. | |
| virtual int GetOutputFd(int child_fd) = 0; | |
| // Starts this process, returning true if successful. | |
| virtual bool Start() = 0; | |
| // Waits for this process to finish. Returns the process's exit | |
| // status if it exited normally, or otherwise returns -1. Note | |
| // that kErrorExitStatus may be returned if an error occurred | |
| // after forking and before execing the child process. | |
| virtual int Wait() = 0; | |
| // Start and wait for this process to finish. Returns same value as | |
| // Wait(). | |
| virtual int Run() = 0; | |
| // Returns the pid of this process or else returns 0 if there is no | |
| // corresponding process (either because it has not yet been started | |
| // or has since exited). | |
| virtual pid_t pid() const = 0; | |
| // Sends |signal| to process and wait |timeout| seconds until it | |
| // dies. If process is not a child, returns immediately with a | |
| // value based on whether kill was successful. If the process is a | |
| // child and |timeout| is non-zero, returns true if the process is | |
| // able to be reaped within the given |timeout| in seconds. | |
| virtual bool Kill(int signal, int timeout) = 0; | |
| // Resets this Process object to refer to the process with |pid|. | |
| // If |pid| is zero, this object no longer refers to a process. | |
| virtual void Reset(pid_t new_pid) = 0; | |
| // Same as Reset but reads the pid from |pid_file|. Returns false | |
| // only when the file cannot be read/parsed. | |
| virtual bool ResetPidByFile(const base::FilePath& pid_file) = 0; | |
| // Releases the process so that on destruction, the process is not killed. | |
| virtual pid_t Release() = 0; | |
| // Returns if |pid| is a currently running process. | |
| static bool ProcessExists(pid_t pid); | |
| // When returned from Wait or Run, indicates an error may have occurred | |
| // creating the process. | |
| enum { kErrorExitStatus = 127 }; | |
| }; | |
| class BRILLO_EXPORT ProcessImpl : public Process { | |
| public: | |
| ProcessImpl(); | |
| virtual ~ProcessImpl(); | |
| virtual void AddArg(const std::string& arg); | |
| virtual void RedirectDevNull(int child_fd); | |
| virtual void RedirectInput(const base::FilePath& input_file); | |
| virtual void RedirectInput(const std::string& input_file); | |
| virtual void RedirectOutput(const base::FilePath& output_file); | |
| virtual void RedirectOutput(const std::string& output_file); | |
| virtual void RedirectOutputToMemory(bool combine); | |
| virtual void RedirectUsingFile(int child_fd, | |
| const base::FilePath& output_file); | |
| virtual void RedirectUsingMemory(int child_fd); | |
| virtual void RedirectUsingPipe(int child_fd, bool is_input); | |
| virtual void BindFd(int parent_fd, int child_fd); | |
| virtual void SetCloseUnusedFileDescriptors(bool close_unused_fds); | |
| virtual void SetUid(uid_t uid); | |
| virtual void SetGid(gid_t gid); | |
| virtual void SetPgid(pid_t pgid); | |
| virtual void SetCapabilities(uint64_t capmask); | |
| virtual void ApplySyscallFilter(const base::FilePath& path); | |
| virtual void EnterNewPidNamespace(); | |
| virtual void SetInheritParentSignalMask(bool inherit); | |
| virtual void SetPreExecCallback(PreExecCallback cb); | |
| virtual void SetSearchPath(bool search_path); | |
| virtual int GetPipe(int child_fd); | |
| virtual std::string GetOutputString(int child_fd); | |
| virtual int GetOutputFd(int child_fd); | |
| virtual bool Start(); | |
| virtual int Wait(); | |
| virtual int Run(); | |
| virtual pid_t pid() const; | |
| virtual bool Kill(int signal, int timeout); | |
| virtual void Reset(pid_t pid); | |
| virtual bool ResetPidByFile(const base::FilePath& pid_file); | |
| virtual pid_t Release(); | |
| protected: | |
| struct PipeInfo { | |
| PipeInfo() : parent_fd_(-1), child_fd_(-1), is_input_(false) {} | |
| // Parent (our) side of the pipe to the child process. | |
| int parent_fd_; | |
| // Child's side of the pipe to the parent. | |
| int child_fd_; | |
| // Is this an input or output pipe from child's perspective. | |
| bool is_input_; | |
| // Is this a bound (pre-existing) file descriptor? | |
| bool is_bound_; | |
| }; | |
| typedef std::map<int, PipeInfo> PipeMap; | |
| enum class FileDescriptorRedirectType { | |
| // Do not redirect the file descriptor in any way. | |
| kIgnore = 0, | |
| // Use a memfd to store the fd contents. | |
| kMemory, | |
| // Use a file to store the file descriptor. | |
| kFile, | |
| }; | |
| struct StandardFileDescriptorInfo { | |
| StandardFileDescriptorInfo() | |
| : parent_fd_(-1), | |
| type_(FileDescriptorRedirectType::kIgnore), | |
| filename_(base::FilePath("")) {} | |
| // (Optional) Parent file descriptor, only exists for kMemory. | |
| int parent_fd_; | |
| // File descriptor redirect type. | |
| FileDescriptorRedirectType type_; | |
| // (Optional) Filename if the type is kFile. | |
| base::FilePath filename_; | |
| }; | |
| void UpdatePid(pid_t new_pid); | |
| bool PopulatePipeMap(); | |
| private: | |
| FRIEND_TEST(ProcessTest, ResetPidByFile); | |
| bool IsFileDescriptorInPipeMap(int fd) const; | |
| void CloseUnusedFileDescriptors(); | |
| // Pid of currently managed process or 0 if no currently managed | |
| // process. pid must not be modified except by calling | |
| // UpdatePid(new_pid). | |
| pid_t pid_; | |
| std::vector<std::string> arguments_; | |
| // Map of child target file descriptors (first) to information about | |
| // pipes created (second). | |
| PipeMap pipe_map_; | |
| // Describes file descriptor state for the child process. | |
| StandardFileDescriptorInfo stdin_, stdout_, stderr_; | |
| uid_t uid_; | |
| gid_t gid_; | |
| pid_t pgid_; | |
| PreExecCallback pre_exec_; | |
| bool search_path_; | |
| // Flag indicating to inherit signal mask from the parent process. It | |
| // is set to false by default, which means by default the child process | |
| // will not inherit signal mask from the parent process. | |
| bool inherit_parent_signal_mask_; | |
| // Flag indicating to close unused file descriptors inherited from the | |
| // parent process when starting the child process, which avoids leaking | |
| // unnecessary file descriptors to the child process. | |
| bool close_unused_file_descriptors_; | |
| }; | |
| } // namespace brillo | |
| #endif // LIBBRILLO_BRILLO_PROCESS_PROCESS_H_ |