| // 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 <fcntl.h> |
| #include <signal.h> |
| #include <sys/stat.h> |
| #include <sys/syscall.h> |
| #include <sys/types.h> |
| #include <sys/wait.h> |
| #include <unistd.h> |
| |
| #include <algorithm> |
| #include <string> |
| #include <utility> |
| #include <vector> |
| |
| #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<syscall_broker::BrokerFilePermission>& 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<bool(void)>& 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_, std::move(ipc_writer), |
| 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_, std::move(ipc_reader)); |
| 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. |