| Index: content/common/sandbox_seccomp_bpf_linux.cc
|
| diff --git a/content/common/sandbox_seccomp_bpf_linux.cc b/content/common/sandbox_seccomp_bpf_linux.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..484fe734a09094133f0f98226ed0e8ff56423fb3
|
| --- /dev/null
|
| +++ b/content/common/sandbox_seccomp_bpf_linux.cc
|
| @@ -0,0 +1,803 @@
|
| +// 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 <asm/unistd.h>
|
| +#include <dlfcn.h>
|
| +#include <errno.h>
|
| +#include <fcntl.h>
|
| +#include <linux/net.h>
|
| +#include <signal.h>
|
| +#include <string.h>
|
| +#include <sys/ioctl.h>
|
| +#include <sys/mman.h>
|
| +#include <sys/prctl.h>
|
| +#include <sys/socket.h>
|
| +#include <sys/stat.h>
|
| +#include <sys/types.h>
|
| +#include <ucontext.h>
|
| +#include <unistd.h>
|
| +
|
| +#include <vector>
|
| +
|
| +#include "base/basictypes.h"
|
| +#include "base/command_line.h"
|
| +#include "base/logging.h"
|
| +#include "build/build_config.h"
|
| +#include "content/common/sandbox_linux.h"
|
| +#include "content/common/sandbox_seccomp_bpf_linux.h"
|
| +#include "content/public/common/content_switches.h"
|
| +#include "sandbox/linux/services/broker_process.h"
|
| +
|
| +// These are the only architectures supported for now.
|
| +#if defined(__i386__) || defined(__x86_64__) || \
|
| + (defined(__arm__) && (defined(__thumb__) || defined(__ARM_EABI__)))
|
| +#define SECCOMP_BPF_SANDBOX
|
| +#endif
|
| +
|
| +#if defined(SECCOMP_BPF_SANDBOX)
|
| +#include "base/posix/eintr_wrapper.h"
|
| +#include "content/common/sandbox_bpf_base_policy_linux.h"
|
| +#include "sandbox/linux/seccomp-bpf-helpers/baseline_policy.h"
|
| +#include "sandbox/linux/seccomp-bpf-helpers/sigsys_handlers.h"
|
| +#include "sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.h"
|
| +#include "sandbox/linux/seccomp-bpf-helpers/syscall_sets.h"
|
| +#include "sandbox/linux/seccomp-bpf/sandbox_bpf.h"
|
| +#include "sandbox/linux/seccomp-bpf/sandbox_bpf_policy.h"
|
| +#include "sandbox/linux/services/linux_syscalls.h"
|
| +
|
| +using sandbox::BaselinePolicy;
|
| +using sandbox::BrokerProcess;
|
| +using sandbox::ErrorCode;
|
| +using sandbox::SandboxBPF;
|
| +using sandbox::SyscallSets;
|
| +using sandbox::arch_seccomp_data;
|
| +
|
| +namespace content {
|
| +
|
| +namespace {
|
| +
|
| +void StartSandboxWithPolicy(sandbox::SandboxBPFPolicy* policy);
|
| +
|
| +inline bool IsChromeOS() {
|
| +#if defined(OS_CHROMEOS)
|
| + return true;
|
| +#else
|
| + return false;
|
| +#endif
|
| +}
|
| +
|
| +inline bool IsArchitectureX86_64() {
|
| +#if defined(__x86_64__)
|
| + return true;
|
| +#else
|
| + return false;
|
| +#endif
|
| +}
|
| +
|
| +inline bool IsArchitectureI386() {
|
| +#if defined(__i386__)
|
| + return true;
|
| +#else
|
| + return false;
|
| +#endif
|
| +}
|
| +
|
| +inline bool IsArchitectureArm() {
|
| +#if defined(__arm__)
|
| + return true;
|
| +#else
|
| + return false;
|
| +#endif
|
| +}
|
| +
|
| +inline bool IsUsingToolKitGtk() {
|
| +#if defined(TOOLKIT_GTK)
|
| + return true;
|
| +#else
|
| + return false;
|
| +#endif
|
| +}
|
| +
|
| +// Policies for the GPU process.
|
| +// TODO(jln): move to gpu/
|
| +
|
| +bool IsAcceleratedVideoDecodeEnabled() {
|
| + // Accelerated video decode is currently enabled on Chrome OS,
|
| + // but not on Linux: crbug.com/137247.
|
| + bool is_enabled = IsChromeOS();
|
| +
|
| + const CommandLine& command_line = *CommandLine::ForCurrentProcess();
|
| + is_enabled = is_enabled &&
|
| + !command_line.HasSwitch(switches::kDisableAcceleratedVideoDecode);
|
| +
|
| + return is_enabled;
|
| +}
|
| +
|
| +intptr_t GpuSIGSYS_Handler(const struct arch_seccomp_data& args,
|
| + void* aux_broker_process) {
|
| + RAW_CHECK(aux_broker_process);
|
| + BrokerProcess* broker_process =
|
| + static_cast<BrokerProcess*>(aux_broker_process);
|
| + switch (args.nr) {
|
| + case __NR_access:
|
| + return broker_process->Access(reinterpret_cast<const char*>(args.args[0]),
|
| + static_cast<int>(args.args[1]));
|
| + case __NR_open:
|
| + return broker_process->Open(reinterpret_cast<const char*>(args.args[0]),
|
| + static_cast<int>(args.args[1]));
|
| + 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;
|
| + }
|
| +}
|
| +
|
| +class GpuProcessPolicy : public SandboxBPFBasePolicy {
|
| + public:
|
| + explicit GpuProcessPolicy(void* broker_process)
|
| + : broker_process_(broker_process) {}
|
| + virtual ~GpuProcessPolicy() {}
|
| +
|
| + virtual ErrorCode EvaluateSyscall(SandboxBPF* sandbox_compiler,
|
| + int system_call_number) const OVERRIDE;
|
| +
|
| + private:
|
| + const void* broker_process_; // Non-owning pointer.
|
| + DISALLOW_COPY_AND_ASSIGN(GpuProcessPolicy);
|
| +};
|
| +
|
| +// Main policy for x86_64/i386. Extended by ArmGpuProcessPolicy.
|
| +ErrorCode GpuProcessPolicy::EvaluateSyscall(SandboxBPF* sandbox,
|
| + int sysno) const {
|
| + switch (sysno) {
|
| + case __NR_ioctl:
|
| +#if defined(__i386__) || defined(__x86_64__)
|
| + // The Nvidia driver uses flags not in the baseline policy
|
| + // (MAP_LOCKED | MAP_EXECUTABLE | MAP_32BIT)
|
| + case __NR_mmap:
|
| +#endif
|
| + // We also hit this on the linux_chromeos bot but don't yet know what
|
| + // weird flags were involved.
|
| + case __NR_mprotect:
|
| + case __NR_sched_getaffinity:
|
| + case __NR_sched_setaffinity:
|
| + case __NR_setpriority:
|
| + return ErrorCode(ErrorCode::ERR_ALLOWED);
|
| + case __NR_access:
|
| + case __NR_open:
|
| + case __NR_openat:
|
| + return sandbox->Trap(GpuSIGSYS_Handler, broker_process_);
|
| + default:
|
| + if (SyscallSets::IsEventFd(sysno))
|
| + return ErrorCode(ErrorCode::ERR_ALLOWED);
|
| +
|
| + // Default on the baseline policy.
|
| + return SandboxBPFBasePolicy::EvaluateSyscall(sandbox, sysno);
|
| + }
|
| +}
|
| +
|
| +class GpuBrokerProcessPolicy : public GpuProcessPolicy {
|
| + public:
|
| + GpuBrokerProcessPolicy() : GpuProcessPolicy(NULL) {}
|
| + virtual ~GpuBrokerProcessPolicy() {}
|
| +
|
| + virtual ErrorCode EvaluateSyscall(SandboxBPF* sandbox_compiler,
|
| + int system_call_number) const OVERRIDE;
|
| +
|
| + private:
|
| + DISALLOW_COPY_AND_ASSIGN(GpuBrokerProcessPolicy);
|
| +};
|
| +
|
| +// x86_64/i386.
|
| +// A GPU broker policy is the same as a GPU policy with open and
|
| +// openat allowed.
|
| +ErrorCode GpuBrokerProcessPolicy::EvaluateSyscall(SandboxBPF* sandbox,
|
| + int sysno) const {
|
| + switch (sysno) {
|
| + case __NR_access:
|
| + case __NR_open:
|
| + case __NR_openat:
|
| + return ErrorCode(ErrorCode::ERR_ALLOWED);
|
| + default:
|
| + return GpuProcessPolicy::EvaluateSyscall(sandbox, sysno);
|
| + }
|
| +}
|
| +
|
| +class ArmGpuProcessPolicy : public GpuProcessPolicy {
|
| + public:
|
| + explicit ArmGpuProcessPolicy(void* broker_process, bool allow_shmat)
|
| + : GpuProcessPolicy(broker_process), allow_shmat_(allow_shmat) {}
|
| + virtual ~ArmGpuProcessPolicy() {}
|
| +
|
| + virtual ErrorCode EvaluateSyscall(SandboxBPF* sandbox_compiler,
|
| + int system_call_number) const OVERRIDE;
|
| +
|
| + private:
|
| + const bool allow_shmat_; // Allow shmat(2).
|
| + DISALLOW_COPY_AND_ASSIGN(ArmGpuProcessPolicy);
|
| +};
|
| +
|
| +// Generic ARM GPU process sandbox, inheriting from GpuProcessPolicy.
|
| +ErrorCode ArmGpuProcessPolicy::EvaluateSyscall(SandboxBPF* sandbox,
|
| + int sysno) const {
|
| +#if defined(__arm__)
|
| + if (allow_shmat_ && sysno == __NR_shmat)
|
| + return ErrorCode(ErrorCode::ERR_ALLOWED);
|
| +#endif // defined(__arm__)
|
| +
|
| + switch (sysno) {
|
| +#if defined(__arm__)
|
| + // ARM GPU sandbox is started earlier so we need to allow networking
|
| + // in the sandbox.
|
| + case __NR_connect:
|
| + case __NR_getpeername:
|
| + case __NR_getsockname:
|
| + case __NR_sysinfo:
|
| + case __NR_uname:
|
| + return ErrorCode(ErrorCode::ERR_ALLOWED);
|
| + // Allow only AF_UNIX for |domain|.
|
| + case __NR_socket:
|
| + case __NR_socketpair:
|
| + return sandbox->Cond(0, ErrorCode::TP_32BIT,
|
| + ErrorCode::OP_EQUAL, AF_UNIX,
|
| + ErrorCode(ErrorCode::ERR_ALLOWED),
|
| + ErrorCode(EPERM));
|
| +#endif // defined(__arm__)
|
| + default:
|
| + if (SyscallSets::IsAdvancedScheduler(sysno))
|
| + return ErrorCode(ErrorCode::ERR_ALLOWED);
|
| +
|
| + // Default to the generic GPU policy.
|
| + return GpuProcessPolicy::EvaluateSyscall(sandbox, sysno);
|
| + }
|
| +}
|
| +
|
| +class ArmGpuBrokerProcessPolicy : public ArmGpuProcessPolicy {
|
| + public:
|
| + ArmGpuBrokerProcessPolicy() : ArmGpuProcessPolicy(NULL, false) {}
|
| + virtual ~ArmGpuBrokerProcessPolicy() {}
|
| +
|
| + virtual ErrorCode EvaluateSyscall(SandboxBPF* sandbox_compiler,
|
| + int system_call_number) const OVERRIDE;
|
| +
|
| + private:
|
| + DISALLOW_COPY_AND_ASSIGN(ArmGpuBrokerProcessPolicy);
|
| +};
|
| +
|
| +// A GPU broker policy is the same as a GPU policy with open and
|
| +// openat allowed.
|
| +ErrorCode ArmGpuBrokerProcessPolicy::EvaluateSyscall(SandboxBPF* sandbox,
|
| + int sysno) const {
|
| + switch (sysno) {
|
| + case __NR_access:
|
| + case __NR_open:
|
| + case __NR_openat:
|
| + return ErrorCode(ErrorCode::ERR_ALLOWED);
|
| + default:
|
| + return ArmGpuProcessPolicy::EvaluateSyscall(sandbox, sysno);
|
| + }
|
| +}
|
| +
|
| +// Policy for renderer and worker processes.
|
| +// TODO(jln): move to renderer/
|
| +
|
| +class RendererOrWorkerProcessPolicy : public SandboxBPFBasePolicy {
|
| + public:
|
| + RendererOrWorkerProcessPolicy() {}
|
| + virtual ~RendererOrWorkerProcessPolicy() {}
|
| +
|
| + virtual ErrorCode EvaluateSyscall(SandboxBPF* sandbox_compiler,
|
| + int system_call_number) const OVERRIDE;
|
| +
|
| + private:
|
| + DISALLOW_COPY_AND_ASSIGN(RendererOrWorkerProcessPolicy);
|
| +};
|
| +
|
| +ErrorCode RendererOrWorkerProcessPolicy::EvaluateSyscall(SandboxBPF* sandbox,
|
| + int sysno) const {
|
| + switch (sysno) {
|
| + case __NR_clone:
|
| + return sandbox::RestrictCloneToThreadsAndEPERMFork(sandbox);
|
| + case __NR_ioctl:
|
| + return sandbox::RestrictIoctl(sandbox);
|
| + case __NR_prctl:
|
| + return sandbox::RestrictPrctl(sandbox);
|
| + // Allow the system calls below.
|
| + case __NR_fdatasync:
|
| + case __NR_fsync:
|
| + case __NR_getpriority:
|
| +#if defined(__i386__) || defined(__x86_64__)
|
| + case __NR_getrlimit:
|
| +#endif
|
| +#if defined(__i386__) || defined(__arm__)
|
| + case __NR_ugetrlimit:
|
| +#endif
|
| + case __NR_mremap: // See crbug.com/149834.
|
| + case __NR_pread64:
|
| + case __NR_pwrite64:
|
| + case __NR_sched_getaffinity:
|
| + case __NR_sched_get_priority_max:
|
| + case __NR_sched_get_priority_min:
|
| + case __NR_sched_getparam:
|
| + case __NR_sched_getscheduler:
|
| + case __NR_sched_setscheduler:
|
| + case __NR_setpriority:
|
| + case __NR_sysinfo:
|
| + case __NR_times:
|
| + case __NR_uname:
|
| + return ErrorCode(ErrorCode::ERR_ALLOWED);
|
| + case __NR_prlimit64:
|
| + return ErrorCode(EPERM); // See crbug.com/160157.
|
| + default:
|
| + if (IsUsingToolKitGtk()) {
|
| +#if defined(__x86_64__) || defined(__arm__)
|
| + if (SyscallSets::IsSystemVSharedMemory(sysno))
|
| + return ErrorCode(ErrorCode::ERR_ALLOWED);
|
| +#endif
|
| +#if defined(__i386__)
|
| + if (SyscallSets::IsSystemVIpc(sysno))
|
| + return ErrorCode(ErrorCode::ERR_ALLOWED);
|
| +#endif
|
| + }
|
| +
|
| + // Default on the content baseline policy.
|
| + return SandboxBPFBasePolicy::EvaluateSyscall(sandbox, sysno);
|
| + }
|
| +}
|
| +
|
| +// Policy for PPAPI plugins.
|
| +// TODO(jln): move to ppapi_plugin/.
|
| +class FlashProcessPolicy : public SandboxBPFBasePolicy {
|
| + public:
|
| + FlashProcessPolicy() {}
|
| + virtual ~FlashProcessPolicy() {}
|
| +
|
| + virtual ErrorCode EvaluateSyscall(SandboxBPF* sandbox_compiler,
|
| + int system_call_number) const OVERRIDE;
|
| +
|
| + private:
|
| + DISALLOW_COPY_AND_ASSIGN(FlashProcessPolicy);
|
| +};
|
| +
|
| +ErrorCode FlashProcessPolicy::EvaluateSyscall(SandboxBPF* sandbox,
|
| + int sysno) const {
|
| + switch (sysno) {
|
| + case __NR_clone:
|
| + return sandbox::RestrictCloneToThreadsAndEPERMFork(sandbox);
|
| + case __NR_pread64:
|
| + case __NR_pwrite64:
|
| + case __NR_sched_get_priority_max:
|
| + case __NR_sched_get_priority_min:
|
| + case __NR_sched_getaffinity:
|
| + case __NR_sched_getparam:
|
| + case __NR_sched_getscheduler:
|
| + case __NR_sched_setscheduler:
|
| + case __NR_times:
|
| + return ErrorCode(ErrorCode::ERR_ALLOWED);
|
| + case __NR_ioctl:
|
| + return ErrorCode(ENOTTY); // Flash Access.
|
| + default:
|
| + if (IsUsingToolKitGtk()) {
|
| +#if defined(__x86_64__) || defined(__arm__)
|
| + if (SyscallSets::IsSystemVSharedMemory(sysno))
|
| + return ErrorCode(ErrorCode::ERR_ALLOWED);
|
| +#endif
|
| +#if defined(__i386__)
|
| + if (SyscallSets::IsSystemVIpc(sysno))
|
| + return ErrorCode(ErrorCode::ERR_ALLOWED);
|
| +#endif
|
| + }
|
| +
|
| + // Default on the baseline policy.
|
| + return SandboxBPFBasePolicy::EvaluateSyscall(sandbox, sysno);
|
| + }
|
| +}
|
| +
|
| +class BlacklistDebugAndNumaPolicy : public SandboxBPFBasePolicy {
|
| + public:
|
| + BlacklistDebugAndNumaPolicy() {}
|
| + virtual ~BlacklistDebugAndNumaPolicy() {}
|
| +
|
| + virtual ErrorCode EvaluateSyscall(SandboxBPF* sandbox_compiler,
|
| + int system_call_number) const OVERRIDE;
|
| +
|
| + private:
|
| + DISALLOW_COPY_AND_ASSIGN(BlacklistDebugAndNumaPolicy);
|
| +};
|
| +
|
| +ErrorCode BlacklistDebugAndNumaPolicy::EvaluateSyscall(SandboxBPF* sandbox,
|
| + int sysno) const {
|
| + if (!SandboxBPF::IsValidSyscallNumber(sysno)) {
|
| + // TODO(jln) we should not have to do that in a trivial policy.
|
| + return ErrorCode(ENOSYS);
|
| + }
|
| + if (SyscallSets::IsDebug(sysno) || SyscallSets::IsNuma(sysno))
|
| + return sandbox->Trap(sandbox::CrashSIGSYS_Handler, NULL);
|
| +
|
| + return ErrorCode(ErrorCode::ERR_ALLOWED);
|
| +}
|
| +
|
| +class AllowAllPolicy : public SandboxBPFBasePolicy {
|
| + public:
|
| + AllowAllPolicy() {}
|
| + virtual ~AllowAllPolicy() {}
|
| +
|
| + virtual ErrorCode EvaluateSyscall(SandboxBPF* sandbox_compiler,
|
| + int system_call_number) const OVERRIDE;
|
| +
|
| + private:
|
| + DISALLOW_COPY_AND_ASSIGN(AllowAllPolicy);
|
| +};
|
| +
|
| +// Allow all syscalls.
|
| +// This will still deny x32 or IA32 calls in 64 bits mode or
|
| +// 64 bits system calls in compatibility mode.
|
| +ErrorCode AllowAllPolicy::EvaluateSyscall(SandboxBPF*, int sysno) const {
|
| + if (!SandboxBPF::IsValidSyscallNumber(sysno)) {
|
| + // TODO(jln) we should not have to do that in a trivial policy.
|
| + return ErrorCode(ENOSYS);
|
| + } else {
|
| + return ErrorCode(ErrorCode::ERR_ALLOWED);
|
| + }
|
| +}
|
| +
|
| +// If a BPF policy is engaged for |process_type|, run a few sanity checks.
|
| +void RunSandboxSanityChecks(const std::string& process_type) {
|
| + if (process_type == switches::kRendererProcess ||
|
| + process_type == switches::kWorkerProcess ||
|
| + process_type == switches::kGpuProcess ||
|
| + process_type == switches::kPpapiPluginProcess) {
|
| + int syscall_ret;
|
| + errno = 0;
|
| +
|
| + // Without the sandbox, this would EBADF.
|
| + syscall_ret = fchmod(-1, 07777);
|
| + CHECK_EQ(-1, syscall_ret);
|
| + CHECK_EQ(EPERM, errno);
|
| +
|
| + // Run most of the sanity checks only in DEBUG mode to avoid a perf.
|
| + // impact.
|
| +#if !defined(NDEBUG)
|
| + // open() must be restricted.
|
| + syscall_ret = open("/etc/passwd", O_RDONLY);
|
| + CHECK_EQ(-1, syscall_ret);
|
| + CHECK_EQ(SandboxBPFBasePolicy::GetFSDeniedErrno(), errno);
|
| +
|
| + // We should never allow the creation of netlink sockets.
|
| + syscall_ret = socket(AF_NETLINK, SOCK_DGRAM, 0);
|
| + CHECK_EQ(-1, syscall_ret);
|
| + CHECK_EQ(EPERM, errno);
|
| +#endif // !defined(NDEBUG)
|
| + }
|
| +}
|
| +
|
| +bool EnableGpuBrokerPolicyCallback() {
|
| + StartSandboxWithPolicy(new GpuBrokerProcessPolicy);
|
| + return true;
|
| +}
|
| +
|
| +bool EnableArmGpuBrokerPolicyCallback() {
|
| + StartSandboxWithPolicy(new ArmGpuBrokerProcessPolicy);
|
| + return true;
|
| +}
|
| +
|
| +// Files needed by the ARM GPU userspace.
|
| +static const char kLibGlesPath[] = "/usr/lib/libGLESv2.so.2";
|
| +static const char kLibEglPath[] = "/usr/lib/libEGL.so.1";
|
| +
|
| +void AddArmMaliGpuWhitelist(std::vector<std::string>* read_whitelist,
|
| + std::vector<std::string>* write_whitelist) {
|
| + // Device file needed by the ARM GPU userspace.
|
| + static const char kMali0Path[] = "/dev/mali0";
|
| +
|
| + // Devices needed for video decode acceleration on ARM.
|
| + static const char kDevMfcDecPath[] = "/dev/mfc-dec";
|
| + static const char kDevGsc1Path[] = "/dev/gsc1";
|
| +
|
| + // Devices needed for video encode acceleration on ARM.
|
| + static const char kDevMfcEncPath[] = "/dev/mfc-enc";
|
| +
|
| + read_whitelist->push_back(kMali0Path);
|
| + read_whitelist->push_back(kDevMfcDecPath);
|
| + read_whitelist->push_back(kDevGsc1Path);
|
| + read_whitelist->push_back(kDevMfcEncPath);
|
| +
|
| + write_whitelist->push_back(kMali0Path);
|
| + write_whitelist->push_back(kDevMfcDecPath);
|
| + write_whitelist->push_back(kDevGsc1Path);
|
| + write_whitelist->push_back(kDevMfcEncPath);
|
| +}
|
| +
|
| +void AddArmTegraGpuWhitelist(std::vector<std::string>* read_whitelist,
|
| + std::vector<std::string>* write_whitelist) {
|
| + // Device files needed by the Tegra GPU userspace.
|
| + static const char kDevNvhostCtrlPath[] = "/dev/nvhost-ctrl";
|
| + static const char kDevNvhostGr2dPath[] = "/dev/nvhost-gr2d";
|
| + static const char kDevNvhostGr3dPath[] = "/dev/nvhost-gr3d";
|
| + static const char kDevNvhostIspPath[] = "/dev/nvhost-isp";
|
| + static const char kDevNvhostViPath[] = "/dev/nvhost-vi";
|
| + static const char kDevNvmapPath[] = "/dev/nvmap";
|
| + static const char kDevTegraSemaPath[] = "/dev/tegra_sema";
|
| +
|
| + read_whitelist->push_back(kDevNvhostCtrlPath);
|
| + read_whitelist->push_back(kDevNvhostGr2dPath);
|
| + read_whitelist->push_back(kDevNvhostGr3dPath);
|
| + read_whitelist->push_back(kDevNvhostIspPath);
|
| + read_whitelist->push_back(kDevNvhostViPath);
|
| + read_whitelist->push_back(kDevNvmapPath);
|
| + read_whitelist->push_back(kDevTegraSemaPath);
|
| +
|
| + write_whitelist->push_back(kDevNvhostCtrlPath);
|
| + write_whitelist->push_back(kDevNvhostGr2dPath);
|
| + write_whitelist->push_back(kDevNvhostGr3dPath);
|
| + write_whitelist->push_back(kDevNvhostIspPath);
|
| + write_whitelist->push_back(kDevNvhostViPath);
|
| + write_whitelist->push_back(kDevNvmapPath);
|
| + write_whitelist->push_back(kDevTegraSemaPath);
|
| +}
|
| +
|
| +void AddArmGpuWhitelist(std::vector<std::string>* read_whitelist,
|
| + std::vector<std::string>* write_whitelist) {
|
| + // On ARM we're enabling the sandbox before the X connection is made,
|
| + // so we need to allow access to |.Xauthority|.
|
| + static const char kXAuthorityPath[] = "/home/chronos/.Xauthority";
|
| + static const char kLdSoCache[] = "/etc/ld.so.cache";
|
| +
|
| + read_whitelist->push_back(kXAuthorityPath);
|
| + read_whitelist->push_back(kLdSoCache);
|
| + read_whitelist->push_back(kLibGlesPath);
|
| + read_whitelist->push_back(kLibEglPath);
|
| +
|
| + AddArmMaliGpuWhitelist(read_whitelist, write_whitelist);
|
| + AddArmTegraGpuWhitelist(read_whitelist, write_whitelist);
|
| +}
|
| +
|
| +// Start a broker process to handle open() inside the sandbox.
|
| +void InitGpuBrokerProcess(bool for_chromeos_arm,
|
| + BrokerProcess** broker_process) {
|
| + static const char kDriRcPath[] = "/etc/drirc";
|
| + static const char kDriCard0Path[] = "/dev/dri/card0";
|
| +
|
| + CHECK(broker_process);
|
| + CHECK(*broker_process == NULL);
|
| +
|
| + bool (*sandbox_callback)(void) = NULL;
|
| +
|
| + // All GPU process policies need these files brokered out.
|
| + std::vector<std::string> read_whitelist;
|
| + read_whitelist.push_back(kDriCard0Path);
|
| + read_whitelist.push_back(kDriRcPath);
|
| +
|
| + std::vector<std::string> write_whitelist;
|
| + write_whitelist.push_back(kDriCard0Path);
|
| +
|
| + if (for_chromeos_arm) {
|
| + // We shouldn't be using this policy on non-ARM architectures.
|
| + DCHECK(IsArchitectureArm());
|
| + AddArmGpuWhitelist(&read_whitelist, &write_whitelist);
|
| + sandbox_callback = EnableArmGpuBrokerPolicyCallback;
|
| + } else {
|
| + sandbox_callback = EnableGpuBrokerPolicyCallback;
|
| + }
|
| +
|
| + *broker_process = new BrokerProcess(SandboxBPFBasePolicy::GetFSDeniedErrno(),
|
| + read_whitelist,
|
| + write_whitelist);
|
| + // Initialize the broker process and give it a sandbox callback.
|
| + CHECK((*broker_process)->Init(sandbox_callback));
|
| +}
|
| +
|
| +// Warms up/preloads resources needed by the policies.
|
| +// Eventually start a broker process and return it in broker_process.
|
| +void WarmupPolicy(bool chromeos_arm_gpu,
|
| + BrokerProcess** broker_process) {
|
| + if (!chromeos_arm_gpu) {
|
| + // Create a new broker process.
|
| + InitGpuBrokerProcess(false /* not for ChromeOS ARM */, broker_process);
|
| +
|
| + if (IsArchitectureX86_64() || IsArchitectureI386()) {
|
| + // Accelerated video decode dlopen()'s some shared objects
|
| + // inside the sandbox, so preload them now.
|
| + if (IsAcceleratedVideoDecodeEnabled()) {
|
| + const char* I965DrvVideoPath = NULL;
|
| +
|
| + if (IsArchitectureX86_64()) {
|
| + I965DrvVideoPath = "/usr/lib64/va/drivers/i965_drv_video.so";
|
| + } else if (IsArchitectureI386()) {
|
| + I965DrvVideoPath = "/usr/lib/va/drivers/i965_drv_video.so";
|
| + }
|
| +
|
| + dlopen(I965DrvVideoPath, RTLD_NOW|RTLD_GLOBAL|RTLD_NODELETE);
|
| + dlopen("libva.so.1", RTLD_NOW|RTLD_GLOBAL|RTLD_NODELETE);
|
| + dlopen("libva-x11.so.1", RTLD_NOW|RTLD_GLOBAL|RTLD_NODELETE);
|
| + }
|
| + }
|
| + } else {
|
| + // ChromeOS ARM GPU policy.
|
| + // Create a new broker process.
|
| + InitGpuBrokerProcess(true /* for ChromeOS ARM */, broker_process);
|
| +
|
| + // Preload the Mali library.
|
| + dlopen("/usr/lib/libmali.so", RTLD_NOW|RTLD_GLOBAL|RTLD_NODELETE);
|
| +
|
| + // Preload the Tegra libraries.
|
| + dlopen("/usr/lib/libnvrm.so", RTLD_NOW|RTLD_GLOBAL|RTLD_NODELETE);
|
| + dlopen("/usr/lib/libnvrm_graphics.so", RTLD_NOW|RTLD_GLOBAL|RTLD_NODELETE);
|
| + dlopen("/usr/lib/libnvos.so", RTLD_NOW|RTLD_GLOBAL|RTLD_NODELETE);
|
| + dlopen("/usr/lib/libnvddk_2d.so", RTLD_NOW|RTLD_GLOBAL|RTLD_NODELETE);
|
| + dlopen("/usr/lib/libardrv_dynamic.so", RTLD_NOW|RTLD_GLOBAL|RTLD_NODELETE);
|
| + dlopen("/usr/lib/libnvwsi.so", RTLD_NOW|RTLD_GLOBAL|RTLD_NODELETE);
|
| + dlopen("/usr/lib/libnvglsi.so", RTLD_NOW|RTLD_GLOBAL|RTLD_NODELETE);
|
| + dlopen("/usr/lib/libcgdrv.so", RTLD_NOW|RTLD_GLOBAL|RTLD_NODELETE);
|
| + }
|
| +}
|
| +
|
| +void StartGpuProcessSandbox(const CommandLine& command_line,
|
| + const std::string& process_type) {
|
| + bool chromeos_arm_gpu = false;
|
| + bool allow_sysv_shm = false;
|
| +
|
| + if (process_type == switches::kGpuProcess) {
|
| + // On Chrome OS ARM, we need a specific GPU process policy.
|
| + if (IsChromeOS() && IsArchitectureArm()) {
|
| + chromeos_arm_gpu = true;
|
| + if (command_line.HasSwitch(switches::kGpuSandboxAllowSysVShm)) {
|
| + allow_sysv_shm = true;
|
| + }
|
| + }
|
| + }
|
| +
|
| + // This should never be destroyed, as after the sandbox is started it is
|
| + // vital to the process. Ownership is transfered to the policies and then to
|
| + // the BPF sandbox which will keep it around to service SIGSYS traps from the
|
| + // kernel.
|
| + BrokerProcess* broker_process = NULL;
|
| + // Warm up resources needed by the policy we're about to enable and
|
| + // eventually start a broker process.
|
| + WarmupPolicy(chromeos_arm_gpu, &broker_process);
|
| +
|
| + scoped_ptr<SandboxBPFBasePolicy> gpu_policy;
|
| + if (chromeos_arm_gpu) {
|
| + gpu_policy.reset(new ArmGpuProcessPolicy(broker_process, allow_sysv_shm));
|
| + } else {
|
| + gpu_policy.reset(new GpuProcessPolicy(broker_process));
|
| + }
|
| + StartSandboxWithPolicy(gpu_policy.release());
|
| +}
|
| +
|
| +// This function takes ownership of |policy|.
|
| +void StartSandboxWithPolicy(sandbox::SandboxBPFPolicy* policy) {
|
| + // Starting the sandbox is a one-way operation. The kernel doesn't allow
|
| + // us to unload a sandbox policy after it has been started. Nonetheless,
|
| + // in order to make the use of the "Sandbox" object easier, we allow for
|
| + // the object to be destroyed after the sandbox has been started. Note that
|
| + // doing so does not stop the sandbox.
|
| + SandboxBPF sandbox;
|
| + sandbox.SetSandboxPolicy(policy);
|
| + sandbox.StartSandbox();
|
| +}
|
| +
|
| +void StartNonGpuSandbox(const std::string& process_type) {
|
| + scoped_ptr<SandboxBPFBasePolicy> policy;
|
| +
|
| + if (process_type == switches::kRendererProcess ||
|
| + process_type == switches::kWorkerProcess) {
|
| + policy.reset(new RendererOrWorkerProcessPolicy);
|
| + } else if (process_type == switches::kPpapiPluginProcess) {
|
| + policy.reset(new FlashProcessPolicy);
|
| + } else if (process_type == switches::kUtilityProcess) {
|
| + policy.reset(new BlacklistDebugAndNumaPolicy);
|
| + } else {
|
| + NOTREACHED();
|
| + policy.reset(new AllowAllPolicy);
|
| + }
|
| +
|
| + StartSandboxWithPolicy(policy.release());
|
| +}
|
| +
|
| +// Initialize the seccomp-bpf sandbox.
|
| +bool StartBPFSandbox(const CommandLine& command_line,
|
| + const std::string& process_type) {
|
| +
|
| + if (process_type == switches::kGpuProcess) {
|
| + StartGpuProcessSandbox(command_line, process_type);
|
| + } else {
|
| + StartNonGpuSandbox(process_type);
|
| + }
|
| +
|
| + RunSandboxSanityChecks(process_type);
|
| + return true;
|
| +}
|
| +
|
| +} // namespace
|
| +
|
| +#endif // SECCOMP_BPF_SANDBOX
|
| +
|
| +// Is seccomp BPF globally enabled?
|
| +bool SandboxSeccompBPF::IsSeccompBPFDesired() {
|
| + const CommandLine& command_line = *CommandLine::ForCurrentProcess();
|
| + if (!command_line.HasSwitch(switches::kNoSandbox) &&
|
| + !command_line.HasSwitch(switches::kDisableSeccompFilterSandbox)) {
|
| + return true;
|
| + } else {
|
| + return false;
|
| + }
|
| +}
|
| +
|
| +bool SandboxSeccompBPF::ShouldEnableSeccompBPF(
|
| + const std::string& process_type) {
|
| +#if defined(SECCOMP_BPF_SANDBOX)
|
| + const CommandLine& command_line = *CommandLine::ForCurrentProcess();
|
| + if (process_type == switches::kGpuProcess)
|
| + return !command_line.HasSwitch(switches::kDisableGpuSandbox);
|
| +
|
| + return true;
|
| +#endif // SECCOMP_BPF_SANDBOX
|
| + return false;
|
| +}
|
| +
|
| +bool SandboxSeccompBPF::SupportsSandbox() {
|
| +#if defined(SECCOMP_BPF_SANDBOX)
|
| + // TODO(jln): pass the saved proc_fd_ from the LinuxSandbox singleton
|
| + // here.
|
| + SandboxBPF::SandboxStatus bpf_sandbox_status =
|
| + SandboxBPF::SupportsSeccompSandbox(-1);
|
| + // Kernel support is what we are interested in here. Other status
|
| + // such as STATUS_UNAVAILABLE (has threads) still indicate kernel support.
|
| + // We make this a negative check, since if there is a bug, we would rather
|
| + // "fail closed" (expect a sandbox to be available and try to start it).
|
| + if (bpf_sandbox_status != SandboxBPF::STATUS_UNSUPPORTED) {
|
| + return true;
|
| + }
|
| +#endif
|
| + return false;
|
| +}
|
| +
|
| +bool SandboxSeccompBPF::StartSandbox(const std::string& process_type) {
|
| +#if defined(SECCOMP_BPF_SANDBOX)
|
| + const CommandLine& command_line = *CommandLine::ForCurrentProcess();
|
| +
|
| + if (IsSeccompBPFDesired() && // Global switches policy.
|
| + ShouldEnableSeccompBPF(process_type) && // Process-specific policy.
|
| + SupportsSandbox()) {
|
| + // If the kernel supports the sandbox, and if the command line says we
|
| + // should enable it, enable it or die.
|
| + bool started_sandbox = StartBPFSandbox(command_line, process_type);
|
| + CHECK(started_sandbox);
|
| + return true;
|
| + }
|
| +#endif
|
| + return false;
|
| +}
|
| +
|
| +bool SandboxSeccompBPF::StartSandboxWithExternalPolicy(
|
| + scoped_ptr<sandbox::SandboxBPFPolicy> policy) {
|
| +#if defined(SECCOMP_BPF_SANDBOX)
|
| + if (IsSeccompBPFDesired() && SupportsSandbox()) {
|
| + CHECK(policy);
|
| + StartSandboxWithPolicy(policy.release());
|
| + return true;
|
| + }
|
| +#endif // defined(SECCOMP_BPF_SANDBOX)
|
| + return false;
|
| +}
|
| +
|
| +scoped_ptr<sandbox::SandboxBPFPolicy>
|
| +SandboxSeccompBPF::GetBaselinePolicy() {
|
| +#if defined(SECCOMP_BPF_SANDBOX)
|
| + return scoped_ptr<sandbox::SandboxBPFPolicy>(new BaselinePolicy);
|
| +#else
|
| + return scoped_ptr<sandbox::SandboxBPFPolicy>();
|
| +#endif // defined(SECCOMP_BPF_SANDBOX)
|
| +}
|
| +
|
| +} // namespace content
|
|
|