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 
     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 
     32 bool ReturnTrue() {
     33   return true;
     34 }
     35 
     36 Process::Process() {
     37 }
     38 
     39 Process::~Process() {
     40 }
     41 
     42 bool Process::ProcessExists(pid_t pid) {
     43   return base::DirectoryExists(
     44       base::FilePath(base::StringPrintf("/proc/%d", pid)));
     45 }
     46 
     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 
     57 ProcessImpl::~ProcessImpl() {
     58   Reset(0);
     59 }
     60 
     61 void ProcessImpl::AddArg(const std::string& arg) {
     62   arguments_.push_back(arg);
     63 }
     64 
     65 void ProcessImpl::RedirectOutput(const std::string& output_file) {
     66   output_file_ = output_file;
     67 }
     68 
     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 
     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 
     89 void ProcessImpl::SetCloseUnusedFileDescriptors(bool close_unused_fds) {
     90   close_unused_file_descriptors_ = close_unused_fds;
     91 }
     92 
     93 void ProcessImpl::SetUid(uid_t uid) {
     94   uid_ = uid;
     95 }
     96 
     97 void ProcessImpl::SetGid(gid_t gid) {
     98   gid_ = gid;
     99 }
    100 
    101 void ProcessImpl::SetCapabilities(uint64_t /*capmask*/) {
    102   // No-op, since ProcessImpl does not support sandboxing.
    103   return;
    104 }
    105 
    106 void ProcessImpl::ApplySyscallFilter(const std::string& /*path*/) {
    107   // No-op, since ProcessImpl does not support sandboxing.
    108   return;
    109 }
    110 
    111 void ProcessImpl::EnterNewPidNamespace() {
    112   // No-op, since ProcessImpl does not support sandboxing.
    113   return;
    114 }
    115 
    116 void ProcessImpl::SetInheritParentSignalMask(bool inherit) {
    117   inherit_parent_signal_mask_ = inherit;
    118 }
    119 
    120 void ProcessImpl::SetPreExecCallback(const PreExecCallback& cb) {
    121   pre_exec_ = cb;
    122 }
    123 
    124 void ProcessImpl::SetSearchPath(bool search_path) {
    125   search_path_ = search_path;
    126 }
    127 
    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 
    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 
    174 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 
    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 
    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 
    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 
    332 int ProcessImpl::Run() {
    333   if (!Start()) {
    334     return -1;
    335   }
    336   return Wait();
    337 }
    338 
    339 pid_t ProcessImpl::pid() {
    340   return pid_;
    341 }
    342 
    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 
    377 void ProcessImpl::UpdatePid(pid_t new_pid) {
    378   pid_ = new_pid;
    379 }
    380 
    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 
    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 
    410 pid_t ProcessImpl::Release() {
    411   pid_t old_pid = pid_;
    412   pid_ = 0;
    413   return old_pid;
    414 }
    415 
    416 }  // namespace brillo
    417