blob: 7ea13174e8135f56bd577e4cef649b44cf502e86 [file] [log] [blame]
// 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/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),
broker_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(broker_policy_, std::move(ipc_writer),
fast_check_in_client_,
quiet_failures_for_tests_));
initialized_ = true;
return true;
}
// 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(broker_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);
}
// static
intptr_t BrokerProcess::SIGSYS_Handler(const sandbox::arch_seccomp_data& args,
void* aux_broker_process) {
RAW_CHECK(aux_broker_process);
auto* broker_process = static_cast<BrokerProcess*>(aux_broker_process);
switch (args.nr) {
#if !defined(__aarch64__)
case __NR_access:
return broker_process->Access(reinterpret_cast<const char*>(args.args[0]),
static_cast<int>(args.args[1]));
case __NR_open:
#if defined(MEMORY_SANITIZER)
// http://crbug.com/372840
__msan_unpoison_string(reinterpret_cast<const char*>(args.args[0]));
#endif
return broker_process->Open(reinterpret_cast<const char*>(args.args[0]),
static_cast<int>(args.args[1]));
#endif // !defined(__aarch64__)
case __NR_faccessat:
if (static_cast<int>(args.args[0]) == AT_FDCWD) {
return broker_process->Access(
reinterpret_cast<const char*>(args.args[1]),
static_cast<int>(args.args[2]));
} else {
return -EPERM;
}
case __NR_openat:
// Allow using openat() as open().
if (static_cast<int>(args.args[0]) == AT_FDCWD) {
return broker_process->Open(reinterpret_cast<const char*>(args.args[1]),
static_cast<int>(args.args[2]));
} else {
return -EPERM;
}
default:
RAW_CHECK(false);
return -ENOSYS;
}
}
} // namespace syscall_broker
} // namespace sandbox.