Home | History | Annotate | Download | only in brillo
      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 
     34 bool ReturnTrue() {
     35   return true;
     36 }
     37 
     38 Process::Process() {
     39 }
     40 
     41 Process::~Process() {
     42 }
     43 
     44 bool Process::ProcessExists(pid_t pid) {
     45   return base::DirectoryExists(
     46       base::FilePath(base::StringPrintf("/proc/%d", pid)));
     47 }
     48 
     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 
     59 ProcessImpl::~ProcessImpl() {
     60   Reset(0);
     61 }
     62 
     63 void ProcessImpl::AddArg(const std::string& arg) {
     64   arguments_.push_back(arg);
     65 }
     66 
     67 void ProcessImpl::RedirectOutput(const std::string& output_file) {
     68   output_file_ = output_file;
     69 }
     70 
     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 
     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 
     91 void ProcessImpl::SetCloseUnusedFileDescriptors(bool close_unused_fds) {
     92   close_unused_file_descriptors_ = close_unused_fds;
     93 }
     94 
     95 void ProcessImpl::SetUid(uid_t uid) {
     96   uid_ = uid;
     97 }
     98 
     99 void ProcessImpl::SetGid(gid_t gid) {
    100   gid_ = gid;
    101 }
    102 
    103 void ProcessImpl::SetCapabilities(uint64_t /*capmask*/) {
    104   // No-op, since ProcessImpl does not support sandboxing.
    105   return;
    106 }
    107 
    108 void ProcessImpl::ApplySyscallFilter(const std::string& /*path*/) {
    109   // No-op, since ProcessImpl does not support sandboxing.
    110   return;
    111 }
    112 
    113 void ProcessImpl::EnterNewPidNamespace() {
    114   // No-op, since ProcessImpl does not support sandboxing.
    115   return;
    116 }
    117 
    118 void ProcessImpl::SetInheritParentSignalMask(bool inherit) {
    119   inherit_parent_signal_mask_ = inherit;
    120 }
    121 
    122 void ProcessImpl::SetPreExecCallback(const PreExecCallback& cb) {
    123   pre_exec_ = cb;
    124 }
    125 
    126 void ProcessImpl::SetSearchPath(bool search_path) {
    127   search_path_ = search_path;
    128 }
    129 
    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 
    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 
    176 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 
    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 
    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 
    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 
    344 int ProcessImpl::Run() {
    345   if (!Start()) {
    346     return -1;
    347   }
    348   return Wait();
    349 }
    350 
    351 pid_t ProcessImpl::pid() {
    352   return pid_;
    353 }
    354 
    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 
    386 void ProcessImpl::UpdatePid(pid_t new_pid) {
    387   pid_ = new_pid;
    388 }
    389 
    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 
    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 
    419 pid_t ProcessImpl::Release() {
    420   pid_t old_pid = pid_;
    421   pid_ = 0;
    422   return old_pid;
    423 }
    424 
    425 }  // namespace brillo
    426