• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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;
ObjectID(const ProcessManager * pm)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 
SetupChild(const map<string,string> & env,bool terminate_with_parent)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 
ProcessManager()63 ProcessManager::ProcessManager() {}
64 
~ProcessManager()65 ProcessManager::~ProcessManager() {}
66 
67 // static
GetInstance()68 ProcessManager* ProcessManager::GetInstance() {
69   return g_process_manager.Pointer();
70 }
71 
Init(EventDispatcher * dispatcher)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 
Stop()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 
StartProcess(const tracked_objects::Location & spawn_source,const base::FilePath & program,const vector<string> & arguments,const map<string,string> & environment,bool terminate_with_parent,const base::Callback<void (int)> & exit_callback)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 
StartProcessInMinijailWithPipes(const tracked_objects::Location & spawn_source,const base::FilePath & program,const std::vector<std::string> & arguments,const std::string & user,const std::string & group,uint64_t capmask,const base::Callback<void (int)> & exit_callback,int * stdin_fd,int * stdout_fd,int * stderr_fd)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 
StopProcess(pid_t pid)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 
StopProcessAndBlock(pid_t pid)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 
KillProcessWithTimeout(pid_t pid,bool kill_signal)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 
KillProcess(pid_t pid,int signal,bool * killed)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 
WaitpidWithTimeout(pid_t pid,unsigned int sleep_ms,unsigned int upper_bound_ms,int tries)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 
UpdateExitCallback(pid_t pid,const base::Callback<void (int)> & new_callback)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 
OnProcessExited(pid_t pid,const siginfo_t & info)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 
ProcessTerminationTimeoutHandler(pid_t pid,bool kill_signal)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 
TerminateProcess(pid_t pid,bool kill_signal)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