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