1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "content/common/sandbox_linux/bpf_gpu_policy_linux.h"
10 #include <sys/socket.h>
12 #include <sys/types.h>
18 #include "base/bind.h"
19 #include "base/command_line.h"
20 #include "base/compiler_specific.h"
21 #include "base/logging.h"
22 #include "base/memory/scoped_ptr.h"
23 #include "build/build_config.h"
24 #include "content/common/sandbox_linux/sandbox_bpf_base_policy_linux.h"
25 #include "content/common/sandbox_linux/sandbox_seccomp_bpf_linux.h"
26 #include "content/common/set_process_title.h"
27 #include "content/public/common/content_switches.h"
28 #include "sandbox/linux/seccomp-bpf-helpers/syscall_sets.h"
29 #include "sandbox/linux/seccomp-bpf/sandbox_bpf.h"
30 #include "sandbox/linux/services/broker_process.h"
31 #include "sandbox/linux/services/linux_syscalls.h"
33 using sandbox::BrokerProcess;
34 using sandbox::ErrorCode;
35 using sandbox::SandboxBPF;
36 using sandbox::SyscallSets;
37 using sandbox::arch_seccomp_data;
43 inline bool IsChromeOS() {
44 #if defined(OS_CHROMEOS)
51 inline bool IsArchitectureX86_64() {
52 #if defined(__x86_64__)
59 inline bool IsArchitectureI386() {
67 inline bool IsArchitectureArm() {
75 bool IsAcceleratedVideoDecodeEnabled() {
76 const CommandLine& command_line = *CommandLine::ForCurrentProcess();
77 return !command_line.HasSwitch(switches::kDisableAcceleratedVideoDecode);
80 intptr_t GpuSIGSYS_Handler(const struct arch_seccomp_data& args,
81 void* aux_broker_process) {
82 RAW_CHECK(aux_broker_process);
83 BrokerProcess* broker_process =
84 static_cast<BrokerProcess*>(aux_broker_process);
87 return broker_process->Access(reinterpret_cast<const char*>(args.args[0]),
88 static_cast<int>(args.args[1]));
90 return broker_process->Open(reinterpret_cast<const char*>(args.args[0]),
91 static_cast<int>(args.args[1]));
93 // Allow using openat() as open().
94 if (static_cast<int>(args.args[0]) == AT_FDCWD) {
96 broker_process->Open(reinterpret_cast<const char*>(args.args[1]),
97 static_cast<int>(args.args[2]));
107 class GpuBrokerProcessPolicy : public GpuProcessPolicy {
109 static sandbox::SandboxBPFPolicy* Create() {
110 return new GpuBrokerProcessPolicy();
112 virtual ~GpuBrokerProcessPolicy() {}
114 virtual ErrorCode EvaluateSyscall(SandboxBPF* sandbox_compiler,
115 int system_call_number) const OVERRIDE;
118 GpuBrokerProcessPolicy() {}
119 DISALLOW_COPY_AND_ASSIGN(GpuBrokerProcessPolicy);
122 // x86_64/i386 or desktop ARM.
123 // A GPU broker policy is the same as a GPU policy with open and
125 ErrorCode GpuBrokerProcessPolicy::EvaluateSyscall(SandboxBPF* sandbox,
131 return ErrorCode(ErrorCode::ERR_ALLOWED);
133 return GpuProcessPolicy::EvaluateSyscall(sandbox, sysno);
137 void UpdateProcessTypeToGpuBroker() {
138 CommandLine::StringVector exec = CommandLine::ForCurrentProcess()->GetArgs();
139 CommandLine::Reset();
140 CommandLine::Init(0, NULL);
141 CommandLine::ForCurrentProcess()->InitFromArgv(exec);
142 CommandLine::ForCurrentProcess()->AppendSwitchASCII(switches::kProcessType,
145 // Update the process title. The argv was already cached by the call to
146 // SetProcessTitleFromCommandLine in content_main_runner.cc, so we can pass
147 // NULL here (we don't have the original argv at this point).
148 SetProcessTitleFromCommandLine(NULL);
151 bool UpdateProcessTypeAndEnableSandbox(
152 sandbox::SandboxBPFPolicy* (*broker_sandboxer_allocator)(void)) {
153 DCHECK(broker_sandboxer_allocator);
154 UpdateProcessTypeToGpuBroker();
155 return SandboxSeccompBPF::StartSandboxWithExternalPolicy(
156 make_scoped_ptr(broker_sandboxer_allocator()));
161 GpuProcessPolicy::GpuProcessPolicy() : broker_process_(NULL) {}
163 GpuProcessPolicy::~GpuProcessPolicy() {}
165 // Main policy for x86_64/i386. Extended by CrosArmGpuProcessPolicy.
166 ErrorCode GpuProcessPolicy::EvaluateSyscall(SandboxBPF* sandbox,
170 #if defined(__i386__) || defined(__x86_64__)
171 // The Nvidia driver uses flags not in the baseline policy
172 // (MAP_LOCKED | MAP_EXECUTABLE | MAP_32BIT)
175 // We also hit this on the linux_chromeos bot but don't yet know what
176 // weird flags were involved.
178 case __NR_sched_getaffinity:
179 case __NR_sched_setaffinity:
180 case __NR_setpriority:
181 return ErrorCode(ErrorCode::ERR_ALLOWED);
185 DCHECK(broker_process_);
186 return sandbox->Trap(GpuSIGSYS_Handler, broker_process_);
188 if (SyscallSets::IsEventFd(sysno))
189 return ErrorCode(ErrorCode::ERR_ALLOWED);
191 // Default on the baseline policy.
192 return SandboxBPFBasePolicy::EvaluateSyscall(sandbox, sysno);
196 bool GpuProcessPolicy::PreSandboxHook() {
197 // Warm up resources needed by the policy we're about to enable and
198 // eventually start a broker process.
199 const bool chromeos_arm_gpu = IsChromeOS() && IsArchitectureArm();
200 // This policy is for x86 or Desktop.
201 DCHECK(!chromeos_arm_gpu);
203 DCHECK(!broker_process());
204 // Create a new broker process.
205 InitGpuBrokerProcess(
206 GpuBrokerProcessPolicy::Create,
207 std::vector<std::string>(), // No extra files in whitelist.
208 std::vector<std::string>());
210 if (IsArchitectureX86_64() || IsArchitectureI386()) {
211 // Accelerated video decode dlopen()'s some shared objects
212 // inside the sandbox, so preload them now.
213 if (IsAcceleratedVideoDecodeEnabled()) {
214 const char* I965DrvVideoPath = NULL;
216 #if defined(OS_TIZEN)
217 if (IsArchitectureX86_64()) {
218 // TODO(halton): Add 64-bit VA driver when 64-bit Tizen support
221 } else if (IsArchitectureI386()) {
222 I965DrvVideoPath = "/usr/lib/dri/i965_dri.so";
225 if (IsArchitectureX86_64()) {
226 I965DrvVideoPath = "/usr/lib64/va/drivers/i965_drv_video.so";
227 } else if (IsArchitectureI386()) {
228 I965DrvVideoPath = "/usr/lib/va/drivers/i965_drv_video.so";
232 dlopen(I965DrvVideoPath, RTLD_NOW|RTLD_GLOBAL|RTLD_NODELETE);
233 dlopen("libva.so.1", RTLD_NOW|RTLD_GLOBAL|RTLD_NODELETE);
234 dlopen("libva-x11.so.1", RTLD_NOW|RTLD_GLOBAL|RTLD_NODELETE);
241 void GpuProcessPolicy::InitGpuBrokerProcess(
242 sandbox::SandboxBPFPolicy* (*broker_sandboxer_allocator)(void),
243 const std::vector<std::string>& read_whitelist_extra,
244 const std::vector<std::string>& write_whitelist_extra) {
245 static const char kDriRcPath[] = "/etc/drirc";
246 static const char kDriCard0Path[] = "/dev/dri/card0";
248 CHECK(broker_process_ == NULL);
250 // All GPU process policies need these files brokered out.
251 std::vector<std::string> read_whitelist;
252 read_whitelist.push_back(kDriCard0Path);
253 read_whitelist.push_back(kDriRcPath);
254 // Add eventual extra files from read_whitelist_extra.
255 read_whitelist.insert(read_whitelist.end(),
256 read_whitelist_extra.begin(),
257 read_whitelist_extra.end());
259 std::vector<std::string> write_whitelist;
260 write_whitelist.push_back(kDriCard0Path);
261 // Add eventual extra files from write_whitelist_extra.
262 write_whitelist.insert(write_whitelist.end(),
263 write_whitelist_extra.begin(),
264 write_whitelist_extra.end());
266 broker_process_ = new BrokerProcess(GetFSDeniedErrno(),
269 // The initialization callback will perform generic initialization and then
270 // call broker_sandboxer_callback.
271 CHECK(broker_process_->Init(base::Bind(&UpdateProcessTypeAndEnableSandbox,
272 broker_sandboxer_allocator)));
275 } // namespace content