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/trap.h"
30 #include "sandbox/linux/services/broker_process.h"
31 #include "sandbox/linux/services/linux_syscalls.h"
33 using sandbox::BrokerProcess
;
34 using sandbox::SyscallSets
;
35 using sandbox::arch_seccomp_data
;
36 using sandbox::bpf_dsl::Allow
;
37 using sandbox::bpf_dsl::ResultExpr
;
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 IsAcceleratedVideoEnabled() {
76 const base::CommandLine
& command_line
=
77 *base::CommandLine::ForCurrentProcess();
78 bool accelerated_encode_enabled
= false;
79 #if defined(OS_CHROMEOS)
80 accelerated_encode_enabled
=
81 !command_line
.HasSwitch(switches::kDisableVaapiAcceleratedVideoEncode
);
83 return !command_line
.HasSwitch(switches::kDisableAcceleratedVideoDecode
) ||
84 accelerated_encode_enabled
;
87 intptr_t GpuSIGSYS_Handler(const struct arch_seccomp_data
& args
,
88 void* aux_broker_process
) {
89 RAW_CHECK(aux_broker_process
);
90 BrokerProcess
* broker_process
=
91 static_cast<BrokerProcess
*>(aux_broker_process
);
94 return broker_process
->Access(reinterpret_cast<const char*>(args
.args
[0]),
95 static_cast<int>(args
.args
[1]));
97 #if defined(MEMORY_SANITIZER)
98 // http://crbug.com/372840
99 __msan_unpoison_string(reinterpret_cast<const char*>(args
.args
[0]));
101 return broker_process
->Open(reinterpret_cast<const char*>(args
.args
[0]),
102 static_cast<int>(args
.args
[1]));
104 // Allow using openat() as open().
105 if (static_cast<int>(args
.args
[0]) == AT_FDCWD
) {
107 broker_process
->Open(reinterpret_cast<const char*>(args
.args
[1]),
108 static_cast<int>(args
.args
[2]));
118 class GpuBrokerProcessPolicy
: public GpuProcessPolicy
{
120 static sandbox::bpf_dsl::SandboxBPFDSLPolicy
* Create() {
121 return new GpuBrokerProcessPolicy();
123 virtual ~GpuBrokerProcessPolicy() {}
125 virtual ResultExpr
EvaluateSyscall(int system_call_number
) const OVERRIDE
;
128 GpuBrokerProcessPolicy() {}
129 DISALLOW_COPY_AND_ASSIGN(GpuBrokerProcessPolicy
);
132 // x86_64/i386 or desktop ARM.
133 // A GPU broker policy is the same as a GPU policy with open and
135 ResultExpr
GpuBrokerProcessPolicy::EvaluateSyscall(int sysno
) const {
142 return GpuProcessPolicy::EvaluateSyscall(sysno
);
146 void UpdateProcessTypeToGpuBroker() {
147 base::CommandLine::StringVector exec
=
148 base::CommandLine::ForCurrentProcess()->GetArgs();
149 base::CommandLine::Reset();
150 base::CommandLine::Init(0, NULL
);
151 base::CommandLine::ForCurrentProcess()->InitFromArgv(exec
);
152 base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
153 switches::kProcessType
, "gpu-broker");
155 // Update the process title. The argv was already cached by the call to
156 // SetProcessTitleFromCommandLine in content_main_runner.cc, so we can pass
157 // NULL here (we don't have the original argv at this point).
158 SetProcessTitleFromCommandLine(NULL
);
161 bool UpdateProcessTypeAndEnableSandbox(sandbox::bpf_dsl::SandboxBPFDSLPolicy
* (
162 *broker_sandboxer_allocator
)(void)) {
163 DCHECK(broker_sandboxer_allocator
);
164 UpdateProcessTypeToGpuBroker();
165 return SandboxSeccompBPF::StartSandboxWithExternalPolicy(
166 make_scoped_ptr(broker_sandboxer_allocator()));
171 GpuProcessPolicy::GpuProcessPolicy() : broker_process_(NULL
) {}
173 GpuProcessPolicy::~GpuProcessPolicy() {}
175 // Main policy for x86_64/i386. Extended by CrosArmGpuProcessPolicy.
176 ResultExpr
GpuProcessPolicy::EvaluateSyscall(int sysno
) const {
179 #if defined(__i386__) || defined(__x86_64__) || defined(__mips__)
180 // The Nvidia driver uses flags not in the baseline policy
181 // (MAP_LOCKED | MAP_EXECUTABLE | MAP_32BIT)
184 // We also hit this on the linux_chromeos bot but don't yet know what
185 // weird flags were involved.
187 // TODO(jln): restrict prctl.
189 case __NR_sched_getaffinity
:
190 case __NR_sched_setaffinity
:
191 case __NR_setpriority
:
196 DCHECK(broker_process_
);
197 return Trap(GpuSIGSYS_Handler
, broker_process_
);
199 if (SyscallSets::IsEventFd(sysno
))
202 // Default on the baseline policy.
203 return SandboxBPFBasePolicy::EvaluateSyscall(sysno
);
207 bool GpuProcessPolicy::PreSandboxHook() {
208 // Warm up resources needed by the policy we're about to enable and
209 // eventually start a broker process.
210 const bool chromeos_arm_gpu
= IsChromeOS() && IsArchitectureArm();
211 // This policy is for x86 or Desktop.
212 DCHECK(!chromeos_arm_gpu
);
214 DCHECK(!broker_process());
215 // Create a new broker process.
216 InitGpuBrokerProcess(
217 GpuBrokerProcessPolicy::Create
,
218 std::vector
<std::string
>(), // No extra files in whitelist.
219 std::vector
<std::string
>());
221 if (IsArchitectureX86_64() || IsArchitectureI386()) {
222 // Accelerated video dlopen()'s some shared objects
223 // inside the sandbox, so preload them now.
224 if (IsAcceleratedVideoEnabled()) {
225 const char* I965DrvVideoPath
= NULL
;
227 if (IsArchitectureX86_64()) {
228 I965DrvVideoPath
= "/usr/lib64/va/drivers/i965_drv_video.so";
229 } else if (IsArchitectureI386()) {
230 I965DrvVideoPath
= "/usr/lib/va/drivers/i965_drv_video.so";
233 dlopen(I965DrvVideoPath
, RTLD_NOW
|RTLD_GLOBAL
|RTLD_NODELETE
);
234 dlopen("libva.so.1", RTLD_NOW
|RTLD_GLOBAL
|RTLD_NODELETE
);
235 dlopen("libva-x11.so.1", RTLD_NOW
|RTLD_GLOBAL
|RTLD_NODELETE
);
242 void GpuProcessPolicy::InitGpuBrokerProcess(
243 sandbox::bpf_dsl::SandboxBPFDSLPolicy
* (*broker_sandboxer_allocator
)(void),
244 const std::vector
<std::string
>& read_whitelist_extra
,
245 const std::vector
<std::string
>& write_whitelist_extra
) {
246 static const char kDriRcPath
[] = "/etc/drirc";
247 static const char kDriCard0Path
[] = "/dev/dri/card0";
249 CHECK(broker_process_
== NULL
);
251 // All GPU process policies need these files brokered out.
252 std::vector
<std::string
> read_whitelist
;
253 read_whitelist
.push_back(kDriCard0Path
);
254 read_whitelist
.push_back(kDriRcPath
);
255 // Add eventual extra files from read_whitelist_extra.
256 read_whitelist
.insert(read_whitelist
.end(),
257 read_whitelist_extra
.begin(),
258 read_whitelist_extra
.end());
260 std::vector
<std::string
> write_whitelist
;
261 write_whitelist
.push_back(kDriCard0Path
);
262 // Add eventual extra files from write_whitelist_extra.
263 write_whitelist
.insert(write_whitelist
.end(),
264 write_whitelist_extra
.begin(),
265 write_whitelist_extra
.end());
267 broker_process_
= new BrokerProcess(GetFSDeniedErrno(),
270 // The initialization callback will perform generic initialization and then
271 // call broker_sandboxer_callback.
272 CHECK(broker_process_
->Init(base::Bind(&UpdateProcessTypeAndEnableSandbox
,
273 broker_sandboxer_allocator
)));
276 } // namespace content