1 // Copyright 2014 The Chromium 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 "sandbox/linux/services/scoped_process.h" 6 7 #include <fcntl.h> 8 #include <signal.h> 9 #include <sys/stat.h> 10 #include <sys/syscall.h> 11 #include <sys/types.h> 12 #include <sys/wait.h> 13 #include <unistd.h> 14 15 #include "base/callback.h" 16 #include "base/logging.h" 17 #include "base/posix/eintr_wrapper.h" 18 #include "build/build_config.h" 19 #include "sandbox/linux/services/syscall_wrappers.h" 20 #include "sandbox/linux/services/thread_helpers.h" 21 22 namespace sandbox { 23 24 namespace { 25 26 const char kSynchronisationChar[] = "D"; 27 28 void WaitForever() { 29 while(true) { 30 pause(); 31 } 32 } 33 34 } // namespace 35 36 ScopedProcess::ScopedProcess(const base::Closure& child_callback) 37 : child_process_id_(-1), process_id_(getpid()) { 38 PCHECK(0 == pipe(pipe_fds_)); 39 #if !defined(THREAD_SANITIZER) 40 // Make sure that we can safely fork(). 41 CHECK(ThreadHelpers::IsSingleThreaded()); 42 #endif 43 child_process_id_ = fork(); 44 PCHECK(0 <= child_process_id_); 45 46 if (0 == child_process_id_) { 47 PCHECK(0 == IGNORE_EINTR(close(pipe_fds_[0]))); 48 pipe_fds_[0] = -1; 49 child_callback.Run(); 50 // Notify the parent that the closure has run. 51 CHECK_EQ(1, HANDLE_EINTR(write(pipe_fds_[1], kSynchronisationChar, 1))); 52 WaitForever(); 53 NOTREACHED(); 54 _exit(1); 55 } 56 57 PCHECK(0 == IGNORE_EINTR(close(pipe_fds_[1]))); 58 pipe_fds_[1] = -1; 59 } 60 61 ScopedProcess::~ScopedProcess() { 62 CHECK(IsOriginalProcess()); 63 if (child_process_id_ >= 0) { 64 PCHECK(0 == kill(child_process_id_, SIGKILL)); 65 siginfo_t process_info; 66 67 PCHECK(0 == HANDLE_EINTR( 68 waitid(P_PID, child_process_id_, &process_info, WEXITED))); 69 } 70 if (pipe_fds_[0] >= 0) { 71 PCHECK(0 == IGNORE_EINTR(close(pipe_fds_[0]))); 72 } 73 if (pipe_fds_[1] >= 0) { 74 PCHECK(0 == IGNORE_EINTR(close(pipe_fds_[1]))); 75 } 76 } 77 78 int ScopedProcess::WaitForExit(bool* got_signaled) { 79 DCHECK(got_signaled); 80 CHECK(IsOriginalProcess()); 81 siginfo_t process_info; 82 // WNOWAIT to make sure that the destructor can wait on the child. 83 int ret = HANDLE_EINTR( 84 waitid(P_PID, child_process_id_, &process_info, WEXITED | WNOWAIT)); 85 PCHECK(0 == ret) << "Did something else wait on the child?"; 86 87 if (process_info.si_code == CLD_EXITED) { 88 *got_signaled = false; 89 } else if (process_info.si_code == CLD_KILLED || 90 process_info.si_code == CLD_DUMPED) { 91 *got_signaled = true; 92 } else { 93 CHECK(false) << "ScopedProcess needs to be extended for si_code " 94 << process_info.si_code; 95 } 96 return process_info.si_status; 97 } 98 99 bool ScopedProcess::WaitForClosureToRun() { 100 char c = 0; 101 int ret = HANDLE_EINTR(read(pipe_fds_[0], &c, 1)); 102 PCHECK(ret >= 0); 103 if (0 == ret) 104 return false; 105 106 CHECK_EQ(c, kSynchronisationChar[0]); 107 return true; 108 } 109 110 // It would be problematic if after a fork(), another process would start using 111 // this object. 112 // This method allows to assert it is not happening. 113 bool ScopedProcess::IsOriginalProcess() { 114 // Make a direct syscall to bypass glibc caching of PIDs. 115 pid_t pid = sys_getpid(); 116 return pid == process_id_; 117 } 118 119 } // namespace sandbox 120