[go: nahoru, domu]

blob: a55b548a8ec755857a95ed535e35d8e5769d9c76 [file] [log] [blame]
// Copyright 2012 The Chromium Authors
// 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 <memory>
#include <string>
#include <utility>
#include <vector>
#include "base/files/file_util.h"
#include "base/functional/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_command.h"
#include "sandbox/linux/syscall_broker/broker_host.h"
#include "sandbox/linux/syscall_broker/broker_permission_list.h"
#include "sandbox/linux/system_headers/linux_syscalls.h"
namespace sandbox {
namespace syscall_broker {
BrokerProcess::BrokerProcess(absl::optional<BrokerSandboxConfig> policy,
BrokerType broker_type,
bool fast_check_in_client,
bool quiet_failures_for_tests)
: policy_(std::move(policy)),
broker_type_(broker_type),
fast_check_in_client_(fast_check_in_client),
quiet_failures_for_tests_(quiet_failures_for_tests) {}
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::ForkSignalBasedBroker(
BrokerSideCallback broker_process_init_callback) {
BrokerChannel::EndPoint ipc_reader, ipc_writer;
BrokerChannel::CreatePair(&ipc_reader, &ipc_writer);
pid_t parent_pid = getpid();
pid_t 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();
// If we already know our policy we can go ahead and create the
// BrokerClient.
CHECK(policy_);
broker_client_ = std::make_unique<BrokerClient>(
*policy_, std::move(ipc_writer), fast_check_in_client_);
broker_pid_ = child_pid;
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(std::move(broker_process_init_callback).Run(*policy_));
BrokerHost broker_host_signal_based(*policy_, std::move(ipc_reader),
parent_pid);
broker_host_signal_based.LoopAndHandleRequests();
_exit(1);
NOTREACHED();
return false;
}
bool BrokerProcess::Fork(BrokerSideCallback broker_process_init_callback) {
CHECK(!initialized_);
#if !defined(THREAD_SANITIZER)
DCHECK_EQ(1, base::GetNumberOfThreads(base::GetCurrentProcessHandle()));
#endif
return ForkSignalBasedBroker(std::move(broker_process_init_callback));
}
bool BrokerProcess::IsSyscallAllowed(int sysno) const {
return IsSyscallBrokerable(sysno, fast_check_in_client_);
}
bool BrokerProcess::IsSyscallBrokerable(int sysno, bool fast_check) const {
CHECK(policy_);
// The syscalls unavailable on aarch64 are all blocked by Android's default
// seccomp policy, even on non-aarch64 architectures. I.e., the syscalls XX()
// with a corresponding XXat() versions are typically unavailable in aarch64
// and are default disabled in Android. So, we should refuse to broker them
// to be consistent with the platform's restrictions.
switch (sysno) {
#if !defined(__aarch64__) && !BUILDFLAG(IS_ANDROID)
case __NR_access:
#endif
case __NR_faccessat:
case __NR_faccessat2:
return !fast_check || policy_->allowed_command_set.test(COMMAND_ACCESS);
#if !defined(__aarch64__) && !BUILDFLAG(IS_ANDROID)
case __NR_mkdir:
#endif
case __NR_mkdirat:
return !fast_check || policy_->allowed_command_set.test(COMMAND_MKDIR);
#if !defined(__aarch64__) && !BUILDFLAG(IS_ANDROID)
case __NR_open:
#endif
case __NR_openat:
return !fast_check || policy_->allowed_command_set.test(COMMAND_OPEN);
#if !defined(__aarch64__) && !BUILDFLAG(IS_ANDROID)
case __NR_readlink:
#endif
case __NR_readlinkat:
return !fast_check || policy_->allowed_command_set.test(COMMAND_READLINK);
#if !defined(__aarch64__) && !BUILDFLAG(IS_ANDROID)
case __NR_rename:
#endif
case __NR_renameat:
case __NR_renameat2:
return !fast_check || policy_->allowed_command_set.test(COMMAND_RENAME);
#if !defined(__aarch64__) && !BUILDFLAG(IS_ANDROID)
case __NR_rmdir:
return !fast_check || policy_->allowed_command_set.test(COMMAND_RMDIR);
#endif
#if !defined(__aarch64__) && !BUILDFLAG(IS_ANDROID)
case __NR_stat:
case __NR_lstat:
#endif
#if defined(__NR_fstatat)
case __NR_fstatat:
#endif
#if defined(__NR_fstatat64)
case __NR_fstatat64:
#endif
#if defined(__x86_64__) || defined(__aarch64__)
case __NR_newfstatat:
#endif
return !fast_check || policy_->allowed_command_set.test(COMMAND_STAT);
#if defined(__i386__) || defined(__arm__) || \
(defined(ARCH_CPU_MIPS_FAMILY) && defined(ARCH_CPU_32_BITS))
case __NR_stat64:
case __NR_lstat64:
// For security purposes, map stat64 to COMMAND_STAT permission. The
// separate COMMAND_STAT64 only exists to broker different-sized
// argument structs.
return !fast_check || policy_->allowed_command_set.test(COMMAND_STAT);
#endif
#if !defined(__aarch64__) && !BUILDFLAG(IS_ANDROID)
case __NR_unlink:
return !fast_check || policy_->allowed_command_set.test(COMMAND_UNLINK);
#endif
case __NR_unlinkat:
// If rmdir() doesn't exist, unlinkat is used with AT_REMOVEDIR.
return !fast_check || policy_->allowed_command_set.test(COMMAND_RMDIR) ||
policy_->allowed_command_set.test(COMMAND_UNLINK);
case __NR_inotify_add_watch:
return !fast_check ||
policy_->allowed_command_set.test(COMMAND_INOTIFY_ADD_WATCH);
default:
return false;
}
}
void BrokerProcess::CloseChannel() {
broker_client_.reset();
}
} // namespace syscall_broker
} // namespace sandbox