Home | History | Annotate | Download | only in shill
      1 //
      2 // Copyright (C) 2015 The Android Open Source Project
      3 //
      4 // Licensed under the Apache License, Version 2.0 (the "License");
      5 // you may not use this file except in compliance with the License.
      6 // You may obtain a copy of the License at
      7 //
      8 //      http://www.apache.org/licenses/LICENSE-2.0
      9 //
     10 // Unless required by applicable law or agreed to in writing, software
     11 // distributed under the License is distributed on an "AS IS" BASIS,
     12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13 // See the License for the specific language governing permissions and
     14 // limitations under the License.
     15 //
     16 
     17 #include "shill/process_manager.h"
     18 
     19 #include <signal.h>
     20 #include <stdlib.h>
     21 #include <sys/prctl.h>
     22 
     23 #include "shill/event_dispatcher.h"
     24 #include "shill/logging.h"
     25 
     26 using base::Closure;
     27 using std::map;
     28 using std::string;
     29 using std::vector;
     30 
     31 namespace shill {
     32 
     33 namespace Logging {
     34 static auto kModuleLogScope = ScopeLogger::kManager;
     35 static string ObjectID(const ProcessManager* pm) { return "process_manager"; }
     36 }
     37 
     38 namespace {
     39 
     40 base::LazyInstance<ProcessManager> g_process_manager =
     41     LAZY_INSTANCE_INITIALIZER;
     42 
     43 static const int kTerminationTimeoutSeconds = 2;
     44 static const int kWaitpidPollTimesForSIGTERM = 10;
     45 static const int kWaitpidPollTimesForSIGKILL = 8;
     46 static const unsigned int kWaitpidPollIntervalUpperBoundMilliseconds = 2000;
     47 static const unsigned int kWaitpidPollInitialIntervalMilliseconds = 4;
     48 
     49 bool SetupChild(const map<string, string>& env, bool terminate_with_parent) {
     50   // Setup environment variables.
     51   clearenv();
     52   for (const auto& key_value : env) {
     53     setenv(key_value.first.c_str(), key_value.second.c_str(), 0);
     54   }
     55   if (terminate_with_parent) {
     56     prctl(PR_SET_PDEATHSIG, SIGTERM);
     57   }
     58   return true;
     59 }
     60 
     61 }  // namespace
     62 
     63 ProcessManager::ProcessManager() {}
     64 
     65 ProcessManager::~ProcessManager() {}
     66 
     67 // static
     68 ProcessManager* ProcessManager::GetInstance() {
     69   return g_process_manager.Pointer();
     70 }
     71 
     72 void ProcessManager::Init(EventDispatcher* dispatcher) {
     73   SLOG(this, 2) << __func__;
     74   CHECK(!async_signal_handler_);
     75   async_signal_handler_.reset(new brillo::AsynchronousSignalHandler());
     76   async_signal_handler_->Init();
     77   process_reaper_.Register(async_signal_handler_.get());
     78   dispatcher_ = dispatcher;
     79   minijail_ = brillo::Minijail::GetInstance();
     80 }
     81 
     82 void ProcessManager::Stop() {
     83   SLOG(this, 2) << __func__;
     84   CHECK(async_signal_handler_);
     85   process_reaper_.Unregister();
     86   async_signal_handler_.reset();
     87 }
     88 
     89 pid_t ProcessManager::StartProcess(
     90     const tracked_objects::Location& spawn_source,
     91     const base::FilePath& program,
     92     const vector<string>& arguments,
     93     const map<string, string>& environment,
     94     bool terminate_with_parent,
     95     const base::Callback<void(int)>& exit_callback) {
     96   SLOG(this, 2) << __func__ << "(" << program.value() << ")";
     97 
     98   // Setup/create child process.
     99   std::unique_ptr<brillo::Process> process(new brillo::ProcessImpl());
    100   process->AddArg(program.value());
    101   for (const auto& option : arguments) {
    102     process->AddArg(option);
    103   }
    104   process->SetCloseUnusedFileDescriptors(true);
    105   process->SetPreExecCallback(
    106       base::Bind(&SetupChild, environment, terminate_with_parent));
    107   if (!process->Start()) {
    108     LOG(ERROR) << "Failed to start child process for " << program.value();
    109     return -1;
    110   }
    111 
    112   // Setup watcher for the child process.
    113   pid_t pid = process->pid();
    114   CHECK(process_reaper_.WatchForChild(
    115       spawn_source,
    116       pid,
    117       base::Bind(&ProcessManager::OnProcessExited,
    118                  weak_factory_.GetWeakPtr(),
    119                  pid)));
    120 
    121   // Release ownership of the child process from the |process| object, so that
    122   // child process will not get killed on destruction of |process| object.
    123   process->Release();
    124 
    125   watched_processes_.emplace(pid, exit_callback);
    126   return pid;
    127 }
    128 
    129 pid_t ProcessManager::StartProcessInMinijailWithPipes(
    130     const tracked_objects::Location& spawn_source,
    131     const base::FilePath& program,
    132     const std::vector<std::string>& arguments,
    133     const std::string& user,
    134     const std::string& group,
    135     uint64_t capmask,
    136     const base::Callback<void(int)>& exit_callback,
    137     int* stdin_fd,
    138     int* stdout_fd,
    139     int* stderr_fd) {
    140   SLOG(this, 2) << __func__ << "(" << program.value() << ")";
    141 
    142   vector<char*> args;
    143   args.push_back(const_cast<char*>(program.value().c_str()));
    144   for (const auto& arg : arguments) {
    145     args.push_back(const_cast<char*>(arg.c_str()));
    146   }
    147   args.push_back(nullptr);
    148 
    149   struct minijail* jail = minijail_->New();
    150 
    151   if (!minijail_->DropRoot(jail, user.c_str(), group.c_str())) {
    152     LOG(ERROR) << "Minijail failed to drop root privileges?";
    153     return -1;
    154   }
    155 #if !defined(__ANDROID__)
    156   // Don't call UseCapabilities on Android since capabilities are not supported
    157   // without LD_PRELOAD, which is not used on Android.
    158   minijail_->UseCapabilities(jail, capmask);
    159 #endif  // __ANDROID__
    160   minijail_->ResetSignalMask(jail);
    161 
    162   pid_t pid;
    163   if (!minijail_->RunPipesAndDestroy(
    164           jail, args, &pid, stdin_fd, stdout_fd, stderr_fd)) {
    165     LOG(ERROR) << "Unable to spawn " << program.value() << " in a jail.";
    166     return -1;
    167   }
    168 
    169   CHECK(process_reaper_.WatchForChild(
    170       spawn_source,
    171       pid,
    172       base::Bind(&ProcessManager::OnProcessExited,
    173                  weak_factory_.GetWeakPtr(),
    174                  pid)));
    175 
    176   watched_processes_.emplace(pid, exit_callback);
    177   return pid;
    178 }
    179 
    180 bool ProcessManager::StopProcess(pid_t pid) {
    181   SLOG(this, 2) << __func__ << "(" << pid << ")";
    182 
    183   if (pending_termination_processes_.find(pid) !=
    184       pending_termination_processes_.end()) {
    185     LOG(ERROR) << "Process " << pid << " already being stopped.";
    186     return false;
    187   }
    188 
    189   if (watched_processes_.find(pid) == watched_processes_.end()) {
    190     LOG(ERROR) << "Process " << pid << " not being watched";
    191     return false;
    192   }
    193   // Caller not interested in watching this process anymore, since the
    194   // process termination is initiated by the caller.
    195   watched_processes_.erase(pid);
    196 
    197   // Attempt to send SIGTERM signal first.
    198   return TerminateProcess(pid, false);
    199 }
    200 
    201 bool ProcessManager::StopProcessAndBlock(pid_t pid) {
    202   SLOG(this, 2) << __func__ << "(" << pid << ")";
    203 
    204   auto terminated_process = pending_termination_processes_.find(pid);
    205 
    206   if (terminated_process != pending_termination_processes_.end()) {
    207     LOG(INFO) << "Process " << pid << " already being stopped.";
    208     terminated_process->second->Cancel();
    209     pending_termination_processes_.erase(terminated_process);
    210   } else {
    211     if (watched_processes_.find(pid) == watched_processes_.end()) {
    212       LOG(ERROR) << "Process " << pid << " not being watched";
    213       return false;
    214     }
    215     // Caller not interested in watching this process anymore, since the
    216     // process termination is initiated by the caller.
    217     watched_processes_.erase(pid);
    218   }
    219 
    220   // We are no longer interested in tracking the exit of this process.
    221   // Also, we will hopefully reap this process ourselves, so remove any
    222   // record of this pid from process_reaper_.
    223   process_reaper_.ForgetChild(pid);
    224 
    225   // Try SIGTERM firstly.
    226   // Send SIGKILL signal if SIGTERM was not handled in a timely manner.
    227   if (KillProcessWithTimeout(pid, false) ||
    228       KillProcessWithTimeout(pid, true)) {
    229     return true;
    230   }
    231 
    232   // In case of killing failure.
    233   LOG(ERROR) << "Timeout waiting for process " << pid << " to be killed.";
    234 
    235   return false;
    236 }
    237 
    238 bool ProcessManager::KillProcessWithTimeout(pid_t pid, bool kill_signal) {
    239   SLOG(this, 2) << __func__ << "(pid: " << pid << ")";
    240 
    241   bool killed = false;
    242   if (KillProcess(pid, kill_signal ? SIGKILL : SIGTERM, &killed)) {
    243     if (killed) {
    244       return true;
    245     }
    246 
    247     int poll_times = kill_signal ? kWaitpidPollTimesForSIGKILL :
    248         kWaitpidPollTimesForSIGTERM;
    249 
    250     if (WaitpidWithTimeout(pid, kWaitpidPollInitialIntervalMilliseconds,
    251                            kWaitpidPollIntervalUpperBoundMilliseconds,
    252                            poll_times)) {
    253       return true;
    254     }
    255   }
    256   return false;
    257 }
    258 
    259 bool ProcessManager::KillProcess(pid_t pid, int signal, bool* killed) {
    260   SLOG(this, 2) << __func__ << "(pid: " << pid << ")";
    261 
    262   if (kill(pid, signal) < 0) {
    263     if (errno == ESRCH) {
    264       SLOG(this, 2) << "Process " << pid << " has exited.";
    265       *killed = true;
    266       return true;
    267     }
    268     PLOG(ERROR) << "Failed to send " << signal <<"signal to process " << pid;
    269     return false;
    270   }
    271   return true;
    272 }
    273 
    274 bool ProcessManager::WaitpidWithTimeout(pid_t pid,
    275                                         unsigned int sleep_ms,
    276                                         unsigned int upper_bound_ms,
    277                                         int tries) {
    278   SLOG(this, 2) << __func__ << "(pid: " << pid << ")";
    279 
    280   while (tries-- > 0) {
    281     if (waitpid(pid, NULL, WNOHANG) == pid) {
    282       return true;
    283     }
    284     usleep(sleep_ms * 1000);
    285     if (2 * sleep_ms < upper_bound_ms) {
    286       sleep_ms *= 2;
    287     }
    288   }
    289   return false;
    290 }
    291 
    292 bool ProcessManager::UpdateExitCallback(
    293     pid_t pid,
    294     const base::Callback<void(int)>& new_callback) {
    295   SLOG(this, 2) << __func__ << "(pid: " << pid << ")";
    296 
    297   const auto process_entry = watched_processes_.find(pid);
    298   if (process_entry == watched_processes_.end()) {
    299     LOG(ERROR) << "Process " << pid << " not being watched";
    300     return false;
    301   }
    302 
    303   process_entry->second = new_callback;
    304   return true;
    305 }
    306 
    307 void ProcessManager::OnProcessExited(pid_t pid, const siginfo_t& info) {
    308   SLOG(this, 2) << __func__ << "(pid: " << pid << ")";
    309 
    310   // Invoke the exit callback if the process is being watched.
    311   auto watched_process = watched_processes_.find(pid);
    312   if (watched_process != watched_processes_.end()) {
    313     base::Callback<void(int)> callback = watched_process->second;
    314     watched_processes_.erase(watched_process);
    315     callback.Run(info.si_status);
    316     return;
    317   }
    318 
    319   // Process terminated by us, cancel timeout handler.
    320   auto terminated_process = pending_termination_processes_.find(pid);
    321   if (terminated_process != pending_termination_processes_.end()) {
    322     terminated_process->second->Cancel();
    323     pending_termination_processes_.erase(terminated_process);
    324     return;
    325   }
    326 
    327   NOTREACHED() << "Unknown process " << pid << " status " << info.si_status;
    328 }
    329 
    330 void ProcessManager::ProcessTerminationTimeoutHandler(pid_t pid,
    331                                                       bool kill_signal) {
    332   SLOG(this, 2) << __func__ << "(pid: " << pid << ")";
    333 
    334   CHECK(pending_termination_processes_.find(pid) !=
    335         pending_termination_processes_.end());
    336   pending_termination_processes_.erase(pid);
    337   // Process still not killed after SIGKILL signal.
    338   if (kill_signal) {
    339     LOG(ERROR) << "Timeout waiting for process " << pid << " to be killed.";
    340     return;
    341   }
    342 
    343   // Retry using SIGKILL signal.
    344   TerminateProcess(pid, true);
    345 }
    346 
    347 bool ProcessManager::TerminateProcess(pid_t pid, bool kill_signal) {
    348   SLOG(this, 2) << __func__
    349                 << "(pid: " << pid << ", "
    350                 << "use_sigkill: " << kill_signal << ")";
    351 
    352   int signal = (kill_signal) ? SIGKILL : SIGTERM;
    353   bool killed = false;
    354   if (!KillProcess(pid, signal, &killed)) {
    355     return false;
    356   }
    357   if (killed) {
    358     return true;
    359   }
    360   std::unique_ptr<TerminationTimeoutCallback> termination_callback(
    361       new TerminationTimeoutCallback(
    362           base::Bind(&ProcessManager::ProcessTerminationTimeoutHandler,
    363                      weak_factory_.GetWeakPtr(),
    364                      pid,
    365                      kill_signal)));
    366   dispatcher_->PostDelayedTask(termination_callback->callback(),
    367                                kTerminationTimeoutSeconds * 1000);
    368   pending_termination_processes_.emplace(pid, std::move(termination_callback));
    369   return true;
    370 }
    371 
    372 }  // namespace shill
    373