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