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