// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "sandbox/linux/syscall_broker/broker_process.h" #include #include #include #include #include #include #include #include #include #include #include "base/callback.h" #include "base/logging.h" #include "base/memory/scoped_ptr.h" #include "base/posix/eintr_wrapper.h" #include "base/process/process_metrics.h" #include "build/build_config.h" #include "sandbox/linux/syscall_broker/broker_channel.h" #include "sandbox/linux/syscall_broker/broker_client.h" #include "sandbox/linux/syscall_broker/broker_host.h" namespace sandbox { namespace syscall_broker { BrokerProcess::BrokerProcess( int denied_errno, const std::vector& permissions, bool fast_check_in_client, bool quiet_failures_for_tests) : initialized_(false), fast_check_in_client_(fast_check_in_client), quiet_failures_for_tests_(quiet_failures_for_tests), broker_pid_(-1), policy_(denied_errno, permissions) { } BrokerProcess::~BrokerProcess() { if (initialized_) { if (broker_client_.get()) { // Closing the socket should be enough to notify the child to die, // unless it has been duplicated. CloseChannel(); } PCHECK(0 == kill(broker_pid_, SIGKILL)); siginfo_t process_info; // Reap the child. int ret = HANDLE_EINTR(waitid(P_PID, broker_pid_, &process_info, WEXITED)); PCHECK(0 == ret); } } bool BrokerProcess::Init( const base::Callback& broker_process_init_callback) { CHECK(!initialized_); BrokerChannel::EndPoint ipc_reader; BrokerChannel::EndPoint ipc_writer; BrokerChannel::CreatePair(&ipc_reader, &ipc_writer); #if !defined(THREAD_SANITIZER) DCHECK_EQ(1, base::GetNumberOfThreads(base::GetCurrentProcessHandle())); #endif int child_pid = fork(); if (child_pid == -1) { return false; } if (child_pid) { // We are the parent and we have just forked our broker process. ipc_reader.reset(); broker_pid_ = child_pid; broker_client_.reset(new BrokerClient(policy_, ipc_writer.Pass(), fast_check_in_client_, quiet_failures_for_tests_)); initialized_ = true; return true; } else { // We are the broker process. Make sure to close the writer's end so that // we get notified if the client disappears. ipc_writer.reset(); CHECK(broker_process_init_callback.Run()); BrokerHost broker_host(policy_, ipc_reader.Pass()); for (;;) { switch (broker_host.HandleRequest()) { case BrokerHost::RequestStatus::LOST_CLIENT: _exit(1); case BrokerHost::RequestStatus::SUCCESS: case BrokerHost::RequestStatus::FAILURE: continue; } } _exit(1); } NOTREACHED(); return false; } void BrokerProcess::CloseChannel() { broker_client_.reset(); } int BrokerProcess::Access(const char* pathname, int mode) const { RAW_CHECK(initialized_); return broker_client_->Access(pathname, mode); } int BrokerProcess::Open(const char* pathname, int flags) const { RAW_CHECK(initialized_); return broker_client_->Open(pathname, flags); } } // namespace syscall_broker } // namespace sandbox.