Home | History | Annotate | Download | only in services
      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 parent. 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