1 // Copyright 2013 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/init_process_reaper.h" 6 7 #include <signal.h> 8 #include <string.h> 9 #include <sys/socket.h> 10 #include <sys/types.h> 11 #include <sys/wait.h> 12 #include <unistd.h> 13 14 #include "base/callback.h" 15 #include "base/logging.h" 16 #include "base/posix/eintr_wrapper.h" 17 18 namespace sandbox { 19 20 namespace { 21 22 void DoNothingSignalHandler(int signal) {} 23 24 } // namespace 25 26 bool CreateInitProcessReaper(base::Closure* post_fork_parent_callback) { 27 int sync_fds[2]; 28 // We want to use send, so we can't use a pipe 29 if (socketpair(AF_UNIX, SOCK_STREAM, 0, sync_fds)) { 30 PLOG(ERROR) << "Failed to create socketpair"; 31 return false; 32 } 33 pid_t child_pid = fork(); 34 if (child_pid == -1) { 35 int close_ret; 36 close_ret = IGNORE_EINTR(close(sync_fds[0])); 37 DPCHECK(!close_ret); 38 close_ret = IGNORE_EINTR(close(sync_fds[1])); 39 DPCHECK(!close_ret); 40 return false; 41 } 42 if (child_pid) { 43 // In the parent, assuming the role of an init process. 44 // The disposition for SIGCHLD cannot be SIG_IGN or wait() will only return 45 // once all of our childs are dead. Since we're init we need to reap childs 46 // as they come. 47 struct sigaction action; 48 memset(&action, 0, sizeof(action)); 49 action.sa_handler = &DoNothingSignalHandler; 50 CHECK(sigaction(SIGCHLD, &action, NULL) == 0); 51 52 int close_ret; 53 close_ret = IGNORE_EINTR(close(sync_fds[0])); 54 DPCHECK(!close_ret); 55 close_ret = shutdown(sync_fds[1], SHUT_RD); 56 DPCHECK(!close_ret); 57 if (post_fork_parent_callback) 58 post_fork_parent_callback->Run(); 59 // Tell the child to continue 60 CHECK(HANDLE_EINTR(send(sync_fds[1], "C", 1, MSG_NOSIGNAL)) == 1); 61 close_ret = IGNORE_EINTR(close(sync_fds[1])); 62 DPCHECK(!close_ret); 63 64 for (;;) { 65 // Loop until we have reaped our one natural child 66 siginfo_t reaped_child_info; 67 int wait_ret = 68 HANDLE_EINTR(waitid(P_ALL, 0, &reaped_child_info, WEXITED)); 69 if (wait_ret) 70 _exit(1); 71 if (reaped_child_info.si_pid == child_pid) { 72 int exit_code = 0; 73 // We're done waiting 74 if (reaped_child_info.si_code == CLD_EXITED) { 75 exit_code = reaped_child_info.si_status; 76 } 77 // Exit with the same exit code as our child. Exit with 0 if we got 78 // signaled. 79 _exit(exit_code); 80 } 81 } 82 } else { 83 // The child needs to wait for the parent to run the callback to avoid a 84 // race condition. 85 int close_ret; 86 close_ret = IGNORE_EINTR(close(sync_fds[1])); 87 DPCHECK(!close_ret); 88 close_ret = shutdown(sync_fds[0], SHUT_WR); 89 DPCHECK(!close_ret); 90 char should_continue; 91 int read_ret = HANDLE_EINTR(read(sync_fds[0], &should_continue, 1)); 92 close_ret = IGNORE_EINTR(close(sync_fds[0])); 93 DPCHECK(!close_ret); 94 if (read_ret == 1) 95 return true; 96 else 97 return false; 98 } 99 } 100 101 } // namespace sandbox. 102