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