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