• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef LIBBRILLO_BRILLO_PROCESS_H_
6 #define LIBBRILLO_BRILLO_PROCESS_H_
7 
8 #include <sys/types.h>
9 
10 #include <map>
11 #include <string>
12 #include <vector>
13 
14 #include <base/bind.h>
15 #include <base/callback.h>
16 #include <base/files/file_path.h>
17 #include <base/strings/string_util.h>
18 #include <base/strings/stringprintf.h>
19 #include <brillo/brillo_export.h>
20 #include <gtest/gtest_prod.h>
21 
22 namespace brillo {
23 // Manages a process.  Can create the process, attach to an existing
24 // process by pid or pid file, and kill the process.  Upon destruction
25 // any managed process is killed with SIGKILL.  Use Release() to
26 // release the process from management.  A given system process may
27 // only be managed by one Process at a time.
28 class BRILLO_EXPORT Process {
29  public:
30   Process();
31   virtual ~Process();
32 
33   // Adds |arg| to the executable command-line to be run.  The
34   // executable name itself is the first argument.
35   virtual void AddArg(const std::string& arg) = 0;
36 
37   // Adds |option| and |value| as an option with a string value to the
38   // command line to be run.
AddStringOption(const std::string & option,const std::string & value)39   inline void AddStringOption(const std::string& option,
40                               const std::string& value) {
41     AddArg(option);
42     AddArg(value);
43   }
44 
45   // Adds |option| and |value| as an option which takes an integer
46   // value to the command line to be run.
AddIntOption(const std::string & option,int value)47   inline void AddIntOption(const std::string& option, int value) {
48     AddArg(option);
49     AddArg(base::StringPrintf("%d", value));
50   }
51 
52   // Redirects to read stdin from |input_file|. |input_file| must not be
53   // a symlink.
54   virtual void RedirectInput(const std::string& input_file) = 0;
55 
56   // Redirects stderr and stdout to |output_file|. |output_file| must not be
57   // a symlink.
58   virtual void RedirectOutput(const std::string& output_file) = 0;
59 
60   // Indicates we want to redirect |child_fd| in the child process's
61   // file table to a pipe.  |child_fd| will be available for reading
62   // from child process's perspective iff |is_input|.
63   virtual void RedirectUsingPipe(int child_fd, bool is_input) = 0;
64 
65   // Binds the given file descriptor in the parent to the given file
66   // descriptor in the child.
67   virtual void BindFd(int parent_fd, int child_fd) = 0;
68 
69   // Set a flag |close_unused_fds| to indicate if the child process
70   // should close all unused file descriptors inherited from the
71   // parent process.  This will not close the file descriptors for
72   // the standard streams (stdin, stdout, and stderr).
73   virtual void SetCloseUnusedFileDescriptors(bool close_unused_fds) = 0;
74 
75   // Set the real/effective/saved user ID of the child process.
76   virtual void SetUid(uid_t uid) = 0;
77 
78   // Set the real/effective/saved group ID of the child process.
79   virtual void SetGid(gid_t gid) = 0;
80 
81   // Set the capabilities assigned to the child process.
82   // NOTE: |capmask| is indeed a mask and should be passed in as the result of
83   // the CAP_TO_MASK(capability) macro, e.g.
84   //     my_process.SetCapabilities(CAP_TO_MASK(CAP_SETUID) |
85   //                                CAP_TO_MASK(CAP_SETGID));
86   // NOTE: supporting this sandboxing feature is optional (provide no-op
87   // implementation if your Process implementation does not support this).
88   virtual void SetCapabilities(uint64_t capmask) = 0;
89 
90   // Apply a syscall filter to the process using the policy file at |path|.
91   // NOTE: supporting this sandboxing feature is optional (provide no-op
92   // implementation if your Process implementation does not support this).
93   virtual void ApplySyscallFilter(const std::string& path) = 0;
94 
95   // Enter new PID namespace when this process is run.
96   // NOTE: supporting this sandboxing feature is optional (provide no-op
97   // implementation if your Process implementation does not support this).
98   virtual void EnterNewPidNamespace() = 0;
99 
100   // Set a flag |inherit| to indicate if the child process intend to
101   // inherit signal mask from the parent process. When |inherit| is
102   // set to true, the child process will inherit signal mask from the
103   // parent process. This could cause unintended side effect, where all
104   // the signals to the child process might be blocked if they are set
105   // in the parent's signal mask.
106   virtual void SetInheritParentSignalMask(bool inherit) = 0;
107 
108   typedef base::Callback<bool(void)> PreExecCallback;
109 
110   // Set the pre-exec callback. This is called after all setup is complete but
111   // before we exec() the process. The callback may return false to cause Start
112   // to return false without starting the process.
113   virtual void SetPreExecCallback(const PreExecCallback& cb) = 0;
114 
115   // Sets whether starting the process should search the system path or not.
116   // By default the system path will not be searched.
117   virtual void SetSearchPath(bool search_path) = 0;
118 
119   // Gets the pipe file descriptor mapped to the process's |child_fd|.
120   virtual int GetPipe(int child_fd) = 0;
121 
122   // Starts this process, returning true if successful.
123   virtual bool Start() = 0;
124 
125   // Waits for this process to finish.  Returns the process's exit
126   // status if it exited normally, or otherwise returns -1.  Note
127   // that kErrorExitStatus may be returned if an error occurred
128   // after forking and before execing the child process.
129   virtual int Wait() = 0;
130 
131   // Start and wait for this process to finish.  Returns same value as
132   // Wait().
133   virtual int Run() = 0;
134 
135   // Returns the pid of this process or else returns 0 if there is no
136   // corresponding process (either because it has not yet been started
137   // or has since exited).
138   virtual pid_t pid() = 0;
139 
140   // Sends |signal| to process and wait |timeout| seconds until it
141   // dies.  If process is not a child, returns immediately with a
142   // value based on whether kill was successful.  If the process is a
143   // child and |timeout| is non-zero, returns true if the process is
144   // able to be reaped within the given |timeout| in seconds.
145   virtual bool Kill(int signal, int timeout) = 0;
146 
147   // Resets this Process object to refer to the process with |pid|.
148   // If |pid| is zero, this object no longer refers to a process.
149   virtual void Reset(pid_t new_pid) = 0;
150 
151   // Same as Reset but reads the pid from |pid_file|.  Returns false
152   // only when the file cannot be read/parsed.
153   virtual bool ResetPidByFile(const std::string& pid_file) = 0;
154 
155   // Releases the process so that on destruction, the process is not killed.
156   virtual pid_t Release() = 0;
157 
158   // Returns if |pid| is a currently running process.
159   static bool ProcessExists(pid_t pid);
160 
161   // When returned from Wait or Run, indicates an error may have occurred
162   // creating the process.
163   enum { kErrorExitStatus = 127 };
164 };
165 
166 class BRILLO_EXPORT ProcessImpl : public Process {
167  public:
168   ProcessImpl();
169   virtual ~ProcessImpl();
170 
171   virtual void AddArg(const std::string& arg);
172   virtual void RedirectInput(const std::string& input_file);
173   virtual void RedirectOutput(const std::string& output_file);
174   virtual void RedirectUsingPipe(int child_fd, bool is_input);
175   virtual void BindFd(int parent_fd, int child_fd);
176   virtual void SetCloseUnusedFileDescriptors(bool close_unused_fds);
177   virtual void SetUid(uid_t uid);
178   virtual void SetGid(gid_t gid);
179   virtual void SetCapabilities(uint64_t capmask);
180   virtual void ApplySyscallFilter(const std::string& path);
181   virtual void EnterNewPidNamespace();
182   virtual void SetInheritParentSignalMask(bool inherit);
183   virtual void SetPreExecCallback(const PreExecCallback& cb);
184   virtual void SetSearchPath(bool search_path);
185   virtual int GetPipe(int child_fd);
186   virtual bool Start();
187   virtual int Wait();
188   virtual int Run();
189   virtual pid_t pid();
190   virtual bool Kill(int signal, int timeout);
191   virtual void Reset(pid_t pid);
192   virtual bool ResetPidByFile(const std::string& pid_file);
193   virtual pid_t Release();
194 
195  protected:
196   struct PipeInfo {
PipeInfoPipeInfo197     PipeInfo() : parent_fd_(-1), child_fd_(-1), is_input_(false) {}
198     // Parent (our) side of the pipe to the child process.
199     int parent_fd_;
200     // Child's side of the pipe to the parent.
201     int child_fd_;
202     // Is this an input or output pipe from child's perspective.
203     bool is_input_;
204     // Is this a bound (pre-existing) file descriptor?
205     bool is_bound_;
206   };
207   typedef std::map<int, PipeInfo> PipeMap;
208 
209   void UpdatePid(pid_t new_pid);
210   bool PopulatePipeMap();
211 
212  private:
213   FRIEND_TEST(ProcessTest, ResetPidByFile);
214 
215   bool IsFileDescriptorInPipeMap(int fd) const;
216   void CloseUnusedFileDescriptors();
217 
218   // Pid of currently managed process or 0 if no currently managed
219   // process.  pid must not be modified except by calling
220   // UpdatePid(new_pid).
221   pid_t pid_;
222   std::string input_file_;
223   std::string output_file_;
224   std::vector<std::string> arguments_;
225   // Map of child target file descriptors (first) to information about
226   // pipes created (second).
227   PipeMap pipe_map_;
228   uid_t uid_;
229   gid_t gid_;
230   PreExecCallback pre_exec_;
231   bool search_path_;
232   // Flag indicating to inherit signal mask from the parent process. It
233   // is set to false by default, which means by default the child process
234   // will not inherit signal mask from the parent process.
235   bool inherit_parent_signal_mask_;
236   // Flag indicating to close unused file descriptors inherited from the
237   // parent process when starting the child process, which avoids leaking
238   // unnecessary file descriptors to the child process.
239   bool close_unused_file_descriptors_;
240 };
241 
242 }  // namespace brillo
243 
244 #endif  // LIBBRILLO_BRILLO_PROCESS_H_
245