• 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 #include "brillo/process.h"
6 
7 #include <fcntl.h>
8 #include <signal.h>
9 #include <stdint.h>
10 #include <sys/stat.h>
11 #include <sys/types.h>
12 #include <sys/wait.h>
13 #include <unistd.h>
14 
15 #include <map>
16 #include <memory>
17 
18 #include <base/files/file_path.h>
19 #include <base/files/file_util.h>
20 #include <base/logging.h>
21 #include <base/memory/ptr_util.h>
22 #include <base/posix/eintr_wrapper.h>
23 #include <base/posix/file_descriptor_shuffle.h>
24 #include <base/process/process_metrics.h>
25 #include <base/strings/string_number_conversions.h>
26 #include <base/strings/string_util.h>
27 #include <base/time/time.h>
28 
29 #ifndef __linux__
30 #define setresuid(_u1, _u2, _u3) setreuid(_u1, _u2)
31 #define setresgid(_g1, _g2, _g3) setregid(_g1, _g2)
32 #endif  // !__linux__
33 
34 namespace brillo {
35 
ReturnTrue()36 bool ReturnTrue() {
37   return true;
38 }
39 
Process()40 Process::Process() {
41 }
42 
~Process()43 Process::~Process() {
44 }
45 
ProcessExists(pid_t pid)46 bool Process::ProcessExists(pid_t pid) {
47   return base::DirectoryExists(
48       base::FilePath(base::StringPrintf("/proc/%d", pid)));
49 }
50 
ProcessImpl()51 ProcessImpl::ProcessImpl()
52     : pid_(0),
53       uid_(-1),
54       gid_(-1),
55       pre_exec_(base::Bind(&ReturnTrue)),
56       search_path_(false),
57       inherit_parent_signal_mask_(false),
58       close_unused_file_descriptors_(false) {
59 }
60 
~ProcessImpl()61 ProcessImpl::~ProcessImpl() {
62   Reset(0);
63 }
64 
AddArg(const std::string & arg)65 void ProcessImpl::AddArg(const std::string& arg) {
66   arguments_.push_back(arg);
67 }
68 
RedirectInput(const std::string & input_file)69 void ProcessImpl::RedirectInput(const std::string& input_file) {
70   input_file_ = input_file;
71 }
72 
RedirectOutput(const std::string & output_file)73 void ProcessImpl::RedirectOutput(const std::string& output_file) {
74   output_file_ = output_file;
75 }
76 
RedirectUsingPipe(int child_fd,bool is_input)77 void ProcessImpl::RedirectUsingPipe(int child_fd, bool is_input) {
78   PipeInfo info;
79   info.is_input_ = is_input;
80   info.is_bound_ = false;
81   pipe_map_[child_fd] = info;
82 }
83 
BindFd(int parent_fd,int child_fd)84 void ProcessImpl::BindFd(int parent_fd, int child_fd) {
85   PipeInfo info;
86   info.is_bound_ = true;
87 
88   // info.child_fd_ is the 'child half' of the pipe, which gets dup2()ed into
89   // place over child_fd. Since we already have the child we want to dup2() into
90   // place, we can set info.child_fd_ to parent_fd and leave info.parent_fd_
91   // invalid.
92   info.child_fd_ = parent_fd;
93   info.parent_fd_ = -1;
94   pipe_map_[child_fd] = info;
95 }
96 
SetCloseUnusedFileDescriptors(bool close_unused_fds)97 void ProcessImpl::SetCloseUnusedFileDescriptors(bool close_unused_fds) {
98   close_unused_file_descriptors_ = close_unused_fds;
99 }
100 
SetUid(uid_t uid)101 void ProcessImpl::SetUid(uid_t uid) {
102   uid_ = uid;
103 }
104 
SetGid(gid_t gid)105 void ProcessImpl::SetGid(gid_t gid) {
106   gid_ = gid;
107 }
108 
SetCapabilities(uint64_t)109 void ProcessImpl::SetCapabilities(uint64_t /*capmask*/) {
110   // No-op, since ProcessImpl does not support sandboxing.
111   return;
112 }
113 
ApplySyscallFilter(const std::string &)114 void ProcessImpl::ApplySyscallFilter(const std::string& /*path*/) {
115   // No-op, since ProcessImpl does not support sandboxing.
116   return;
117 }
118 
EnterNewPidNamespace()119 void ProcessImpl::EnterNewPidNamespace() {
120   // No-op, since ProcessImpl does not support sandboxing.
121   return;
122 }
123 
SetInheritParentSignalMask(bool inherit)124 void ProcessImpl::SetInheritParentSignalMask(bool inherit) {
125   inherit_parent_signal_mask_ = inherit;
126 }
127 
SetPreExecCallback(const PreExecCallback & cb)128 void ProcessImpl::SetPreExecCallback(const PreExecCallback& cb) {
129   pre_exec_ = cb;
130 }
131 
SetSearchPath(bool search_path)132 void ProcessImpl::SetSearchPath(bool search_path) {
133   search_path_ = search_path;
134 }
135 
GetPipe(int child_fd)136 int ProcessImpl::GetPipe(int child_fd) {
137   PipeMap::iterator i = pipe_map_.find(child_fd);
138   if (i == pipe_map_.end())
139     return -1;
140   else
141     return i->second.parent_fd_;
142 }
143 
PopulatePipeMap()144 bool ProcessImpl::PopulatePipeMap() {
145   for (PipeMap::iterator i = pipe_map_.begin(); i != pipe_map_.end(); ++i) {
146     if (i->second.is_bound_) {
147       // already have a parent fd, and the child fd gets dup()ed later.
148       continue;
149     }
150     int pipefds[2];
151     if (pipe(pipefds) < 0) {
152       int saved_errno = errno;
153       LOG(ERROR) << "pipe call failed with: " << saved_errno;
154       return false;
155     }
156     if (i->second.is_input_) {
157       // pipe is an input from the prospective of the child.
158       i->second.parent_fd_ = pipefds[1];
159       i->second.child_fd_ = pipefds[0];
160     } else {
161       i->second.parent_fd_ = pipefds[0];
162       i->second.child_fd_ = pipefds[1];
163     }
164   }
165   return true;
166 }
167 
IsFileDescriptorInPipeMap(int fd) const168 bool ProcessImpl::IsFileDescriptorInPipeMap(int fd) const {
169   for (const auto& pipe : pipe_map_) {
170     if (fd == pipe.second.parent_fd_ ||
171         fd == pipe.second.child_fd_ ||
172         fd == pipe.first) {
173       return true;
174     }
175   }
176   return false;
177 }
178 
CloseUnusedFileDescriptors()179 void ProcessImpl::CloseUnusedFileDescriptors() {
180   size_t max_fds = base::GetMaxFds();
181   for (size_t i = 0; i < max_fds; i++) {
182     const int fd = static_cast<int>(i);
183 
184     // Ignore STD file descriptors.
185     if (fd == STDIN_FILENO || fd == STDOUT_FILENO || fd == STDERR_FILENO) {
186       continue;
187     }
188 
189     // Ignore file descriptors used by the PipeMap, they will be handled
190     // by this process later on.
191     if (IsFileDescriptorInPipeMap(fd)) {
192       continue;
193     }
194 
195     // Since we're just trying to close anything we can find,
196     // ignore any error return values of close().
197     IGNORE_EINTR(close(fd));
198   }
199 }
200 
Start()201 bool ProcessImpl::Start() {
202   // If no arguments are provided, fail.
203   if (arguments_.empty()) {
204     return false;
205   }
206   std::unique_ptr<char* []> argv =
207       std::make_unique<char* []>(arguments_.size() + 1);
208 
209   for (size_t i = 0; i < arguments_.size(); ++i)
210     argv[i] = const_cast<char*>(arguments_[i].c_str());
211 
212   argv[arguments_.size()] = nullptr;
213 
214   if (!PopulatePipeMap()) {
215     LOG(ERROR) << "Failing to start because pipe creation failed";
216     return false;
217   }
218 
219   pid_t pid = fork();
220   int saved_errno = errno;
221   if (pid < 0) {
222     LOG(ERROR) << "Fork failed: " << saved_errno;
223     Reset(0);
224     return false;
225   }
226 
227   if (pid == 0) {
228     // Executing inside the child process.
229     // Close unused file descriptors.
230     if (close_unused_file_descriptors_) {
231       CloseUnusedFileDescriptors();
232     }
233 
234     base::InjectiveMultimap fd_shuffle;
235     for (const auto& it : pipe_map_) {
236       // Close parent's side of the child pipes.
237       if (it.second.parent_fd_ != -1)
238         IGNORE_EINTR(close(it.second.parent_fd_));
239 
240       fd_shuffle.emplace_back(it.second.child_fd_, it.first, true);
241     }
242 
243     if (!base::ShuffleFileDescriptors(&fd_shuffle)) {
244       PLOG(ERROR) << "Could not shuffle file descriptors";
245       _exit(kErrorExitStatus);
246     }
247 
248     if (!input_file_.empty()) {
249       int input_handle =
250           HANDLE_EINTR(open(input_file_.c_str(),
251                             O_RDONLY | O_NOFOLLOW | O_NOCTTY));
252       if (input_handle < 0) {
253         PLOG(ERROR) << "Could not open " << input_file_;
254         // Avoid exit() to avoid atexit handlers from parent.
255         _exit(kErrorExitStatus);
256       }
257 
258       // It's possible input_handle is already stdin. But if not, we need
259       // to dup into that file descriptor and close the original.
260       if (input_handle != STDIN_FILENO) {
261         if (HANDLE_EINTR(dup2(input_handle, STDIN_FILENO)) < 0) {
262           PLOG(ERROR) << "Could not dup fd to stdin for " << input_file_;
263           _exit(kErrorExitStatus);
264         }
265         IGNORE_EINTR(close(input_handle));
266       }
267     }
268 
269     if (!output_file_.empty()) {
270       int output_handle = HANDLE_EINTR(open(
271           output_file_.c_str(), O_CREAT | O_WRONLY | O_TRUNC | O_NOFOLLOW,
272           0666));
273       if (output_handle < 0) {
274         PLOG(ERROR) << "Could not create " << output_file_;
275         // Avoid exit() to avoid atexit handlers from parent.
276         _exit(kErrorExitStatus);
277       }
278       HANDLE_EINTR(dup2(output_handle, STDOUT_FILENO));
279       HANDLE_EINTR(dup2(output_handle, STDERR_FILENO));
280       // Only close output_handle if it does not happen to be one of
281       // the two standard file descriptors we are trying to redirect.
282       if (output_handle != STDOUT_FILENO && output_handle != STDERR_FILENO) {
283         IGNORE_EINTR(close(output_handle));
284       }
285     }
286     if (gid_ != static_cast<gid_t>(-1) && setresgid(gid_, gid_, gid_) < 0) {
287       int saved_errno = errno;
288       LOG(ERROR) << "Unable to set GID to " << gid_ << ": " << saved_errno;
289       _exit(kErrorExitStatus);
290     }
291     if (uid_ != static_cast<uid_t>(-1) && setresuid(uid_, uid_, uid_) < 0) {
292       int saved_errno = errno;
293       LOG(ERROR) << "Unable to set UID to " << uid_ << ": " << saved_errno;
294       _exit(kErrorExitStatus);
295     }
296     if (!pre_exec_.Run()) {
297       LOG(ERROR) << "Pre-exec callback failed";
298       _exit(kErrorExitStatus);
299     }
300     // Reset signal mask for the child process if not inheriting signal mask
301     // from the parent process.
302     if (!inherit_parent_signal_mask_) {
303       sigset_t signal_mask;
304       CHECK_EQ(0, sigemptyset(&signal_mask));
305       CHECK_EQ(0, sigprocmask(SIG_SETMASK, &signal_mask, nullptr));
306     }
307     if (search_path_) {
308       execvp(argv[0], &argv[0]);
309     } else {
310       execv(argv[0], &argv[0]);
311     }
312     PLOG(ERROR) << "Exec of " << argv[0] << " failed";
313     _exit(kErrorExitStatus);
314   } else {
315     // Still executing inside the parent process with known child pid.
316     arguments_.clear();
317     UpdatePid(pid);
318     // Close our copy of child side pipes only if we created those pipes.
319     for (const auto& i : pipe_map_) {
320       if (!i.second.is_bound_) {
321         IGNORE_EINTR(close(i.second.child_fd_));
322       }
323     }
324   }
325   return true;
326 }
327 
Wait()328 int ProcessImpl::Wait() {
329   int status = 0;
330   if (pid_ == 0) {
331     LOG(ERROR) << "Process not running";
332     return -1;
333   }
334   if (HANDLE_EINTR(waitpid(pid_, &status, 0)) < 0) {
335     int saved_errno = errno;
336     LOG(ERROR) << "Problem waiting for pid " << pid_ << ": " << saved_errno;
337     return -1;
338   }
339   pid_t old_pid = pid_;
340   // Update the pid to 0 - do not Reset as we do not want to try to
341   // kill the process that has just exited.
342   UpdatePid(0);
343   if (!WIFEXITED(status)) {
344     DCHECK(WIFSIGNALED(status)) << old_pid
345                                 << " neither exited, nor died on a signal?";
346     LOG(ERROR) << "Process " << old_pid
347                << " did not exit normally: " << WTERMSIG(status);
348     return -1;
349   }
350   return WEXITSTATUS(status);
351 }
352 
Run()353 int ProcessImpl::Run() {
354   if (!Start()) {
355     return -1;
356   }
357   return Wait();
358 }
359 
pid()360 pid_t ProcessImpl::pid() {
361   return pid_;
362 }
363 
Kill(int signal,int timeout)364 bool ProcessImpl::Kill(int signal, int timeout) {
365   if (pid_ == 0) {
366     // Passing pid == 0 to kill is committing suicide.  Check specifically.
367     LOG(ERROR) << "Process not running";
368     return false;
369   }
370   if (kill(pid_, signal) < 0) {
371     PLOG(ERROR) << "Unable to send signal to " << pid_;
372     return false;
373   }
374   base::TimeTicks start_signal = base::TimeTicks::Now();
375   do {
376     int status = 0;
377     pid_t w = waitpid(pid_, &status, WNOHANG);
378     if (w < 0) {
379       if (errno == ECHILD)
380         return true;
381       PLOG(ERROR) << "Waitpid returned " << w;
382       return false;
383     }
384     if (w > 0) {
385       Reset(0);
386       return true;
387     }
388     usleep(100);
389   } while ((base::TimeTicks::Now() - start_signal).InSecondsF() <= timeout);
390   LOG(INFO) << "process " << pid_ << " did not exit from signal " << signal
391             << " in " << timeout << " seconds";
392   return false;
393 }
394 
UpdatePid(pid_t new_pid)395 void ProcessImpl::UpdatePid(pid_t new_pid) {
396   pid_ = new_pid;
397 }
398 
Reset(pid_t new_pid)399 void ProcessImpl::Reset(pid_t new_pid) {
400   arguments_.clear();
401   // Close our side of all pipes to this child giving the child to
402   // handle sigpipes and shutdown nicely, though likely it won't
403   // have time.
404   for (PipeMap::iterator i = pipe_map_.begin(); i != pipe_map_.end(); ++i)
405     IGNORE_EINTR(close(i->second.parent_fd_));
406   pipe_map_.clear();
407   if (pid_)
408     Kill(SIGKILL, 0);
409   UpdatePid(new_pid);
410 }
411 
ResetPidByFile(const std::string & pid_file)412 bool ProcessImpl::ResetPidByFile(const std::string& pid_file) {
413   std::string contents;
414   if (!base::ReadFileToString(base::FilePath(pid_file), &contents)) {
415     LOG(ERROR) << "Could not read pid file" << pid_file;
416     return false;
417   }
418   base::TrimWhitespaceASCII(contents, base::TRIM_TRAILING, &contents);
419   int64_t pid_int64 = 0;
420   if (!base::StringToInt64(contents, &pid_int64)) {
421     LOG(ERROR) << "Unexpected pid file contents";
422     return false;
423   }
424   Reset(pid_int64);
425   return true;
426 }
427 
Release()428 pid_t ProcessImpl::Release() {
429   pid_t old_pid = pid_;
430   pid_ = 0;
431   return old_pid;
432 }
433 
434 }  // namespace brillo
435