Chromium Code Reviews| Index: content/common/sandbox_linux/sandbox_bpf_gpu_policy_linux.cc |
| diff --git a/content/common/sandbox_linux/sandbox_bpf_gpu_policy_linux.cc b/content/common/sandbox_linux/sandbox_bpf_gpu_policy_linux.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..a4a6aeb70d18da9e4a64ad6f3b19388821e6567e |
| --- /dev/null |
| +++ b/content/common/sandbox_linux/sandbox_bpf_gpu_policy_linux.cc |
| @@ -0,0 +1,242 @@ |
| +// Copyright (c) 2013 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 "content/common/sandbox_linux/sandbox_bpf_gpu_policy_linux.h" |
| + |
| +#include <dlfcn.h> |
| +#include <errno.h> |
| +#include <fcntl.h> |
| +#include <sys/socket.h> |
| +#include <sys/stat.h> |
| +#include <sys/types.h> |
| +#include <unistd.h> |
| + |
| +#include <string> |
| +#include <vector> |
| + |
| +#include "base/command_line.h" |
| +#include "base/compiler_specific.h" |
| +#include "base/logging.h" |
| +#include "base/memory/scoped_ptr.h" |
| +#include "content/common/sandbox_linux/sandbox_bpf_base_policy_linux.h" |
| +#include "content/common/sandbox_linux/sandbox_seccomp_bpf_linux.h" |
| +#include "content/public/common/content_switches.h" |
| +#include "sandbox/linux/seccomp-bpf-helpers/syscall_sets.h" |
| +#include "sandbox/linux/seccomp-bpf/sandbox_bpf.h" |
| +#include "sandbox/linux/services/broker_process.h" |
| +#include "sandbox/linux/services/linux_syscalls.h" |
| + |
| +using sandbox::BrokerProcess; |
| +using sandbox::ErrorCode; |
| +using sandbox::SandboxBPF; |
| +using sandbox::SyscallSets; |
| +using sandbox::arch_seccomp_data; |
| + |
| +namespace content { |
| + |
| +namespace { |
| + |
| +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 |
| +} |
| + |
| +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 && |
|
Robert Sesek
2013/12/12 21:33:48
Could switch to &=
jln (very slow on Chromium)
2013/12/12 22:15:14
Done.
|
| + !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 GpuBrokerProcessPolicy : public GpuProcessPolicy { |
| + public: |
| + GpuBrokerProcessPolicy() {} |
| + virtual ~GpuBrokerProcessPolicy() {} |
| + |
| + virtual ErrorCode EvaluateSyscall(SandboxBPF* sandbox_compiler, |
| + int system_call_number) const OVERRIDE; |
| + |
| + private: |
| + DISALLOW_COPY_AND_ASSIGN(GpuBrokerProcessPolicy); |
| +}; |
| + |
| +// x86_64/i386 or desktop ARM. |
| +// 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); |
| + } |
| +} |
| + |
| +bool EnableGpuBrokerPolicyCallback() { |
| + return SandboxSeccompBPF::StartSandboxWithExternalPolicy( |
| + scoped_ptr<sandbox::SandboxBPFPolicy>(new GpuBrokerProcessPolicy)); |
| +} |
| + |
| +} // namespace |
| + |
| +// Main policy for x86_64/i386. Extended by CrosArmGpuProcessPolicy. |
| +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: |
| + DCHECK(broker_process_); |
| + 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); |
| + } |
| +} |
| + |
| +bool GpuProcessPolicy::PreSandboxHook() { |
| + // Warm up resources needed by the policy we're about to enable and |
| + // eventually start a broker process. |
| + const bool chromeos_arm_gpu = IsChromeOS() && IsArchitectureArm(); |
| + DCHECK(!chromeos_arm_gpu); |
| + |
| + DCHECK(!broker_process()); |
| + // Create a new broker process. |
| + InitGpuBrokerProcess( |
| + EnableGpuBrokerPolicyCallback, |
| + std::vector<std::string>(), // No extra files in whitelist. |
| + std::vector<std::string>()); |
| + |
| + 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); |
| + } |
| + } |
| + |
| + return true; |
| +} |
| + |
| +void GpuProcessPolicy::InitGpuBrokerProcess( |
| + bool (*broker_sandboxer_callback)(void), |
| + const std::vector<std::string>& read_whitelist_extra, |
| + const std::vector<std::string>& write_whitelist_extra) { |
| + static const char kDriRcPath[] = "/etc/drirc"; |
| + static const char kDriCard0Path[] = "/dev/dri/card0"; |
| + |
| + CHECK(broker_process_ == 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); |
| + // Add eventual extra files from read_whitelist_extra. |
| + read_whitelist.insert(read_whitelist.end(), |
| + read_whitelist_extra.begin(), |
| + read_whitelist_extra.end()); |
| + |
| + std::vector<std::string> write_whitelist; |
| + write_whitelist.push_back(kDriCard0Path); |
| + // Add eventual extra files from write_whitelist_extra. |
| + write_whitelist.insert(write_whitelist.end(), |
| + write_whitelist_extra.begin(), |
| + write_whitelist_extra.end()); |
| + |
| + broker_process_ = new BrokerProcess(GetFSDeniedErrno(), |
| + read_whitelist, |
| + write_whitelist); |
| + // Initialize the broker process and give it a sandbox callback. |
| + CHECK(broker_process_->Init(broker_sandboxer_callback)); |
| +} |
| + |
| +} // namespace content |