xref: /aosp_15_r20/external/libbrillo/brillo/process.cc (revision 1a96fba65179ea7d3f56207137718607415c5953)
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 #ifdef __BIONIC__
8 #include <android/fdsan.h>
9 #endif
10 
11 #include <fcntl.h>
12 #include <signal.h>
13 #include <stdint.h>
14 #include <sys/mman.h>
15 #include <sys/stat.h>
16 #include <sys/types.h>
17 #include <sys/wait.h>
18 #include <unistd.h>
19 
20 #include <map>
21 #include <memory>
22 
23 #include <base/files/file_path.h>
24 #include <base/files/file_util.h>
25 #include <base/logging.h>
26 #include <base/posix/eintr_wrapper.h>
27 #include <base/posix/file_descriptor_shuffle.h>
28 #include <base/process/process_metrics.h>
29 #include <base/strings/string_number_conversions.h>
30 #include <base/strings/string_util.h>
31 #include <base/time/time.h>
32 
33 #ifndef __linux__
34 #define setresuid(_u1, _u2, _u3) setreuid(_u1, _u2)
35 #define setresgid(_g1, _g2, _g3) setregid(_g1, _g2)
36 #endif  // !__linux__
37 
38 namespace brillo {
39 
ReturnTrue()40 bool ReturnTrue() {
41   return true;
42 }
43 
Process()44 Process::Process() {}
45 
~Process()46 Process::~Process() {}
47 
ProcessExists(pid_t pid)48 bool Process::ProcessExists(pid_t pid) {
49   return base::DirectoryExists(
50       base::FilePath(base::StringPrintf("/proc/%d", pid)));
51 }
52 
ProcessImpl()53 ProcessImpl::ProcessImpl()
54     : pid_(0),
55       uid_(-1),
56       gid_(-1),
57       pre_exec_(base::Bind(&ReturnTrue)),
58       search_path_(false),
59       inherit_parent_signal_mask_(false),
60       close_unused_file_descriptors_(false) {}
61 
~ProcessImpl()62 ProcessImpl::~ProcessImpl() {
63   Reset(0);
64 }
65 
AddArg(const std::string & arg)66 void ProcessImpl::AddArg(const std::string& arg) {
67   arguments_.push_back(arg);
68 }
69 
RedirectInput(const std::string & input_file)70 void ProcessImpl::RedirectInput(const std::string& input_file) {
71   input_file_ = input_file;
72 }
73 
RedirectOutput(const std::string & output_file)74 void ProcessImpl::RedirectOutput(const std::string& output_file) {
75   output_file_ = output_file;
76 }
77 
RedirectUsingPipe(int child_fd,bool is_input)78 void ProcessImpl::RedirectUsingPipe(int child_fd, bool is_input) {
79   PipeInfo info;
80   info.is_input_ = is_input;
81   info.is_bound_ = false;
82   pipe_map_[child_fd] = info;
83 }
84 
BindFd(int parent_fd,int child_fd)85 void ProcessImpl::BindFd(int parent_fd, int child_fd) {
86   PipeInfo info;
87   info.is_bound_ = true;
88 
89   // info.child_fd_ is the 'child half' of the pipe, which gets dup2()ed into
90   // place over child_fd. Since we already have the child we want to dup2() into
91   // place, we can set info.child_fd_ to parent_fd and leave info.parent_fd_
92   // invalid.
93   info.child_fd_ = parent_fd;
94   info.parent_fd_ = -1;
95   pipe_map_[child_fd] = info;
96 }
97 
SetCloseUnusedFileDescriptors(bool close_unused_fds)98 void ProcessImpl::SetCloseUnusedFileDescriptors(bool close_unused_fds) {
99   close_unused_file_descriptors_ = close_unused_fds;
100 }
101 
SetUid(uid_t uid)102 void ProcessImpl::SetUid(uid_t uid) {
103   uid_ = uid;
104 }
105 
SetGid(gid_t gid)106 void ProcessImpl::SetGid(gid_t gid) {
107   gid_ = gid;
108 }
109 
SetCapabilities(uint64_t)110 void ProcessImpl::SetCapabilities(uint64_t /*capmask*/) {
111   // No-op, since ProcessImpl does not support sandboxing.
112   return;
113 }
114 
ApplySyscallFilter(const std::string &)115 void ProcessImpl::ApplySyscallFilter(const std::string& /*path*/) {
116   // No-op, since ProcessImpl does not support sandboxing.
117   return;
118 }
119 
EnterNewPidNamespace()120 void ProcessImpl::EnterNewPidNamespace() {
121   enter_new_pid_namespace_ = true;
122   return;
123 }
124 
SetInheritParentSignalMask(bool inherit)125 void ProcessImpl::SetInheritParentSignalMask(bool inherit) {
126   inherit_parent_signal_mask_ = inherit;
127 }
128 
SetPreExecCallback(const PreExecCallback & cb)129 void ProcessImpl::SetPreExecCallback(const PreExecCallback& cb) {
130   pre_exec_ = cb;
131 }
132 
SetSearchPath(bool search_path)133 void ProcessImpl::SetSearchPath(bool search_path) {
134   search_path_ = search_path;
135 }
136 
GetPipe(int child_fd)137 int ProcessImpl::GetPipe(int child_fd) {
138   PipeMap::iterator i = pipe_map_.find(child_fd);
139   if (i == pipe_map_.end())
140     return -1;
141   else
142     return i->second.parent_fd_;
143 }
144 
PopulatePipeMap()145 bool ProcessImpl::PopulatePipeMap() {
146   for (PipeMap::iterator i = pipe_map_.begin(); i != pipe_map_.end(); ++i) {
147     if (i->second.is_bound_) {
148       // already have a parent fd, and the child fd gets dup()ed later.
149       continue;
150     }
151     int pipefds[2];
152     if (pipe(pipefds) < 0) {
153       int saved_errno = errno;
154       LOG(ERROR) << "pipe call failed with: " << saved_errno;
155       return false;
156     }
157     if (i->second.is_input_) {
158       // pipe is an input from the prospective of the child.
159       i->second.parent_fd_ = pipefds[1];
160       i->second.child_fd_ = pipefds[0];
161     } else {
162       i->second.parent_fd_ = pipefds[0];
163       i->second.child_fd_ = pipefds[1];
164     }
165   }
166   return true;
167 }
168 
IsFileDescriptorInPipeMap(int fd) const169 bool ProcessImpl::IsFileDescriptorInPipeMap(int fd) const {
170   for (const auto& pipe : pipe_map_) {
171     if (fd == pipe.second.parent_fd_ || fd == pipe.second.child_fd_ ||
172         fd == pipe.first) {
173       return true;
174     }
175   }
176   return false;
177 }
178 
CloseUnusedFileDescriptors()179 void ProcessImpl::CloseUnusedFileDescriptors() {
180   size_t max_fds = base::GetMaxFds();
181   for (size_t i = 0; i < max_fds; i++) {
182     const int fd = static_cast<int>(i);
183 
184     // Ignore STD file descriptors.
185     if (fd == STDIN_FILENO || fd == STDOUT_FILENO || fd == STDERR_FILENO) {
186       continue;
187     }
188 
189     // Ignore file descriptors used by the PipeMap, they will be handled
190     // by this process later on.
191     if (IsFileDescriptorInPipeMap(fd)) {
192       continue;
193     }
194 
195     // Since we're just trying to close anything we can find,
196     // ignore any error return values of close().
197     IGNORE_EINTR(close(fd));
198   }
199 }
200 
Start()201 bool ProcessImpl::Start() {
202   // If no arguments are provided, fail.
203   if (arguments_.empty()) {
204     return false;
205   }
206   std::unique_ptr<char*[]> argv =
207       std::make_unique<char*[]>(arguments_.size() + 1);
208 
209   for (size_t i = 0; i < arguments_.size(); ++i)
210     argv[i] = const_cast<char*>(arguments_[i].c_str());
211 
212   argv[arguments_.size()] = nullptr;
213 
214   if (!PopulatePipeMap()) {
215     LOG(ERROR) << "Failing to start because pipe creation failed";
216     return false;
217   }
218 
219   // 64K child stack size
220   constexpr size_t kStackSize = 64 * 1024;
221   // clone() expects a pointer which points to top most byte of the stack
222   auto stack = reinterpret_cast<char*>(mmap(nullptr,
223                                             kStackSize,
224                                             PROT_READ | PROT_WRITE,
225                                             MAP_ANON | MAP_PRIVATE,
226                                             -1,
227                                             0)) +
228                kStackSize;
229   struct State {
230     ProcessImpl* p;
231     char** argv;
232   } state{};
233   state.p = this;
234   state.argv = argv.get();
235   int flags = SIGCHLD;
236   if (enter_new_pid_namespace_) {
237     flags |= CLONE_NEWPID;
238   }
239   int pid = clone(
240       [](void* arg) {
241         State* s = reinterpret_cast<State*>(arg);
242         s->p->ExecChildProcess(s->argv);
243         return 0;
244       },
245       stack,
246       flags,
247       &state);
248 
249   // Still executing inside the parent process with known child pid.
250   arguments_.clear();
251   UpdatePid(pid);
252   // Close our copy of child side pipes only if we created those pipes.
253   for (const auto& i : pipe_map_) {
254     if (!i.second.is_bound_) {
255       IGNORE_EINTR(close(i.second.child_fd_));
256     }
257   }
258   return true;
259 }
260 
ExecChildProcess(char ** argv)261 void ProcessImpl::ExecChildProcess(char** argv) {
262 #ifdef __BIONIC__
263   // Disable fdsan and fdtrack post-fork, so we don't falsely trigger on
264   // processes that fork, close all of their fds, and then exec.
265   android_fdsan_set_error_level(ANDROID_FDSAN_ERROR_LEVEL_DISABLED);
266 #endif
267   // Executing inside the child process.
268   // Close unused file descriptors.
269   if (close_unused_file_descriptors_) {
270     CloseUnusedFileDescriptors();
271   }
272 
273   base::InjectiveMultimap fd_shuffle;
274   for (const auto& it : pipe_map_) {
275     // Close parent's side of the child pipes.
276     if (it.second.parent_fd_ != -1)
277       IGNORE_EINTR(close(it.second.parent_fd_));
278 
279     fd_shuffle.emplace_back(it.second.child_fd_, it.first, true);
280   }
281 
282   if (!base::ShuffleFileDescriptors(&fd_shuffle)) {
283     PLOG(ERROR) << "Could not shuffle file descriptors";
284     _exit(kErrorExitStatus);
285   }
286 
287   if (!input_file_.empty()) {
288     int input_handle = HANDLE_EINTR(
289         open(input_file_.c_str(), O_RDONLY | O_NOFOLLOW | O_NOCTTY));
290     if (input_handle < 0) {
291       PLOG(ERROR) << "Could not open " << input_file_;
292       // Avoid exit() to avoid atexit handlers from parent.
293       _exit(kErrorExitStatus);
294     }
295 
296     // It's possible input_handle is already stdin. But if not, we need
297     // to dup into that file descriptor and close the original.
298     if (input_handle != STDIN_FILENO) {
299       if (HANDLE_EINTR(dup2(input_handle, STDIN_FILENO)) < 0) {
300         PLOG(ERROR) << "Could not dup fd to stdin for " << input_file_;
301         _exit(kErrorExitStatus);
302       }
303       IGNORE_EINTR(close(input_handle));
304     }
305   }
306 
307   if (!output_file_.empty()) {
308     int output_handle = HANDLE_EINTR(open(
309         output_file_.c_str(), O_CREAT | O_WRONLY | O_TRUNC | O_NOFOLLOW, 0666));
310     if (output_handle < 0) {
311       PLOG(ERROR) << "Could not create " << output_file_;
312       // Avoid exit() to avoid atexit handlers from parent.
313       _exit(kErrorExitStatus);
314     }
315     HANDLE_EINTR(dup2(output_handle, STDOUT_FILENO));
316     HANDLE_EINTR(dup2(output_handle, STDERR_FILENO));
317     // Only close output_handle if it does not happen to be one of
318     // the two standard file descriptors we are trying to redirect.
319     if (output_handle != STDOUT_FILENO && output_handle != STDERR_FILENO) {
320       IGNORE_EINTR(close(output_handle));
321     }
322   }
323   if (gid_ != static_cast<gid_t>(-1) && setresgid(gid_, gid_, gid_) < 0) {
324     int saved_errno = errno;
325     LOG(ERROR) << "Unable to set GID to " << gid_ << ": " << saved_errno;
326     _exit(kErrorExitStatus);
327   }
328   if (uid_ != static_cast<uid_t>(-1) && setresuid(uid_, uid_, uid_) < 0) {
329     int saved_errno = errno;
330     LOG(ERROR) << "Unable to set UID to " << uid_ << ": " << saved_errno;
331     _exit(kErrorExitStatus);
332   }
333   if (!pre_exec_.Run()) {
334     LOG(ERROR) << "Pre-exec callback failed";
335     _exit(kErrorExitStatus);
336   }
337   // Reset signal mask for the child process if not inheriting signal mask
338   // from the parent process.
339   if (!inherit_parent_signal_mask_) {
340     sigset_t signal_mask;
341     CHECK_EQ(0, sigemptyset(&signal_mask));
342     CHECK_EQ(0, sigprocmask(SIG_SETMASK, &signal_mask, nullptr));
343   }
344   if (search_path_) {
345     execvp(argv[0], &argv[0]);
346   } else {
347     execv(argv[0], &argv[0]);
348   }
349   PLOG(ERROR) << "Exec of " << argv[0] << " failed";
350   _exit(kErrorExitStatus);
351 }
352 
Wait()353 int ProcessImpl::Wait() {
354   int status = 0;
355   if (pid_ == 0) {
356     LOG(ERROR) << "Process not running";
357     return -1;
358   }
359   if (HANDLE_EINTR(waitpid(pid_, &status, 0)) < 0) {
360     int saved_errno = errno;
361     LOG(ERROR) << "Problem waiting for pid " << pid_ << ": " << saved_errno;
362     return -1;
363   }
364   pid_t old_pid = pid_;
365   // Update the pid to 0 - do not Reset as we do not want to try to
366   // kill the process that has just exited.
367   UpdatePid(0);
368   if (!WIFEXITED(status)) {
369     DCHECK(WIFSIGNALED(status))
370         << old_pid << " neither exited, nor died on a signal?";
371     LOG(ERROR) << "Process " << old_pid
372                << " did not exit normally: " << WTERMSIG(status);
373     return -1;
374   }
375   return WEXITSTATUS(status);
376 }
377 
Run()378 int ProcessImpl::Run() {
379   if (!Start()) {
380     return -1;
381   }
382   return Wait();
383 }
384 
pid()385 pid_t ProcessImpl::pid() {
386   return pid_;
387 }
388 
Kill(int signal,int timeout)389 bool ProcessImpl::Kill(int signal, int timeout) {
390   if (pid_ == 0) {
391     // Passing pid == 0 to kill is committing suicide.  Check specifically.
392     LOG(ERROR) << "Process not running";
393     return false;
394   }
395   if (kill(pid_, signal) < 0) {
396     PLOG(ERROR) << "Unable to send signal to " << pid_;
397     return false;
398   }
399   base::TimeTicks start_signal = base::TimeTicks::Now();
400   do {
401     int status = 0;
402     pid_t w = waitpid(pid_, &status, WNOHANG);
403     if (w < 0) {
404       if (errno == ECHILD)
405         return true;
406       PLOG(ERROR) << "Waitpid returned " << w;
407       return false;
408     }
409     if (w > 0) {
410       Reset(0);
411       return true;
412     }
413     usleep(100);
414   } while ((base::TimeTicks::Now() - start_signal).InSecondsF() <= timeout);
415   LOG(INFO) << "process " << pid_ << " did not exit from signal " << signal
416             << " in " << timeout << " seconds";
417   return false;
418 }
419 
UpdatePid(pid_t new_pid)420 void ProcessImpl::UpdatePid(pid_t new_pid) {
421   pid_ = new_pid;
422 }
423 
Reset(pid_t new_pid)424 void ProcessImpl::Reset(pid_t new_pid) {
425   arguments_.clear();
426   // Close our side of all pipes to this child giving the child to
427   // handle sigpipes and shutdown nicely, though likely it won't
428   // have time.
429   for (PipeMap::iterator i = pipe_map_.begin(); i != pipe_map_.end(); ++i)
430     IGNORE_EINTR(close(i->second.parent_fd_));
431   pipe_map_.clear();
432   if (pid_)
433     Kill(SIGKILL, 0);
434   UpdatePid(new_pid);
435 }
436 
ResetPidByFile(const std::string & pid_file)437 bool ProcessImpl::ResetPidByFile(const std::string& pid_file) {
438   std::string contents;
439   if (!base::ReadFileToString(base::FilePath(pid_file), &contents)) {
440     LOG(ERROR) << "Could not read pid file" << pid_file;
441     return false;
442   }
443   base::TrimWhitespaceASCII(contents, base::TRIM_TRAILING, &contents);
444   int64_t pid_int64 = 0;
445   if (!base::StringToInt64(contents, &pid_int64)) {
446     LOG(ERROR) << "Unexpected pid file contents";
447     return false;
448   }
449   Reset(pid_int64);
450   return true;
451 }
452 
Release()453 pid_t ProcessImpl::Release() {
454   pid_t old_pid = pid_;
455   pid_ = 0;
456   return old_pid;
457 }
458 
459 }  // namespace brillo
460