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