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 IsAcceleratedVideoEnabled() {
76 const CommandLine
& command_line
= *CommandLine::ForCurrentProcess();
77 bool accelerated_encode_enabled
= false;
78 #if defined(OS_CHROMEOS)
79 accelerated_encode_enabled
=
80 command_line
.HasSwitch(switches::kEnableVaapiAcceleratedVideoEncode
);
82 return !command_line
.HasSwitch(switches::kDisableAcceleratedVideoDecode
) ||
83 accelerated_encode_enabled
;
86 intptr_t GpuSIGSYS_Handler(const struct arch_seccomp_data
& args
,
87 void* aux_broker_process
) {
88 RAW_CHECK(aux_broker_process
);
89 BrokerProcess
* broker_process
=
90 static_cast<BrokerProcess
*>(aux_broker_process
);
93 return broker_process
->Access(reinterpret_cast<const char*>(args
.args
[0]),
94 static_cast<int>(args
.args
[1]));
96 #if defined(MEMORY_SANITIZER)
97 // http://crbug.com/372840
98 __msan_unpoison_string(reinterpret_cast<const char*>(args
.args
[0]));
100 return broker_process
->Open(reinterpret_cast<const char*>(args
.args
[0]),
101 static_cast<int>(args
.args
[1]));
103 // Allow using openat() as open().
104 if (static_cast<int>(args
.args
[0]) == AT_FDCWD
) {
106 broker_process
->Open(reinterpret_cast<const char*>(args
.args
[1]),
107 static_cast<int>(args
.args
[2]));
117 class GpuBrokerProcessPolicy
: public GpuProcessPolicy
{
119 static sandbox::SandboxBPFPolicy
* Create() {
120 return new GpuBrokerProcessPolicy();
122 virtual ~GpuBrokerProcessPolicy() {}
124 virtual ErrorCode
EvaluateSyscall(SandboxBPF
* sandbox_compiler
,
125 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 ErrorCode
GpuBrokerProcessPolicy::EvaluateSyscall(SandboxBPF
* sandbox
,
141 return ErrorCode(ErrorCode::ERR_ALLOWED
);
143 return GpuProcessPolicy::EvaluateSyscall(sandbox
, sysno
);
147 void UpdateProcessTypeToGpuBroker() {
148 CommandLine::StringVector exec
= CommandLine::ForCurrentProcess()->GetArgs();
149 CommandLine::Reset();
150 CommandLine::Init(0, NULL
);
151 CommandLine::ForCurrentProcess()->InitFromArgv(exec
);
152 CommandLine::ForCurrentProcess()->AppendSwitchASCII(switches::kProcessType
,
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(
162 sandbox::SandboxBPFPolicy
* (*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 ErrorCode
GpuProcessPolicy::EvaluateSyscall(SandboxBPF
* sandbox
,
180 #if defined(__i386__) || defined(__x86_64__)
181 // The Nvidia driver uses flags not in the baseline policy
182 // (MAP_LOCKED | MAP_EXECUTABLE | MAP_32BIT)
185 // We also hit this on the linux_chromeos bot but don't yet know what
186 // weird flags were involved.
188 // TODO(jln): restrict prctl.
190 case __NR_sched_getaffinity
:
191 case __NR_sched_setaffinity
:
192 case __NR_setpriority
:
193 return ErrorCode(ErrorCode::ERR_ALLOWED
);
197 DCHECK(broker_process_
);
198 return sandbox
->Trap(GpuSIGSYS_Handler
, broker_process_
);
200 if (SyscallSets::IsEventFd(sysno
))
201 return ErrorCode(ErrorCode::ERR_ALLOWED
);
203 // Default on the baseline policy.
204 return SandboxBPFBasePolicy::EvaluateSyscall(sandbox
, sysno
);
208 bool GpuProcessPolicy::PreSandboxHook() {
209 // Warm up resources needed by the policy we're about to enable and
210 // eventually start a broker process.
211 const bool chromeos_arm_gpu
= IsChromeOS() && IsArchitectureArm();
212 // This policy is for x86 or Desktop.
213 DCHECK(!chromeos_arm_gpu
);
215 DCHECK(!broker_process());
216 // Create a new broker process.
217 InitGpuBrokerProcess(
218 GpuBrokerProcessPolicy::Create
,
219 std::vector
<std::string
>(), // No extra files in whitelist.
220 std::vector
<std::string
>());
222 if (IsArchitectureX86_64() || IsArchitectureI386()) {
223 // Accelerated video dlopen()'s some shared objects
224 // inside the sandbox, so preload them now.
225 if (IsAcceleratedVideoEnabled()) {
226 const char* I965DrvVideoPath
= NULL
;
228 if (IsArchitectureX86_64()) {
229 I965DrvVideoPath
= "/usr/lib64/va/drivers/i965_drv_video.so";
230 } else if (IsArchitectureI386()) {
231 I965DrvVideoPath
= "/usr/lib/va/drivers/i965_drv_video.so";
234 dlopen(I965DrvVideoPath
, RTLD_NOW
|RTLD_GLOBAL
|RTLD_NODELETE
);
235 dlopen("libva.so.1", RTLD_NOW
|RTLD_GLOBAL
|RTLD_NODELETE
);
236 dlopen("libva-x11.so.1", RTLD_NOW
|RTLD_GLOBAL
|RTLD_NODELETE
);
243 void GpuProcessPolicy::InitGpuBrokerProcess(
244 sandbox::SandboxBPFPolicy
* (*broker_sandboxer_allocator
)(void),
245 const std::vector
<std::string
>& read_whitelist_extra
,
246 const std::vector
<std::string
>& write_whitelist_extra
) {
247 static const char kDriRcPath
[] = "/etc/drirc";
248 static const char kDriCard0Path
[] = "/dev/dri/card0";
250 CHECK(broker_process_
== NULL
);
252 // All GPU process policies need these files brokered out.
253 std::vector
<std::string
> read_whitelist
;
254 read_whitelist
.push_back(kDriCard0Path
);
255 read_whitelist
.push_back(kDriRcPath
);
256 // Add eventual extra files from read_whitelist_extra.
257 read_whitelist
.insert(read_whitelist
.end(),
258 read_whitelist_extra
.begin(),
259 read_whitelist_extra
.end());
261 std::vector
<std::string
> write_whitelist
;
262 write_whitelist
.push_back(kDriCard0Path
);
263 // Add eventual extra files from write_whitelist_extra.
264 write_whitelist
.insert(write_whitelist
.end(),
265 write_whitelist_extra
.begin(),
266 write_whitelist_extra
.end());
268 broker_process_
= new BrokerProcess(GetFSDeniedErrno(),
271 // The initialization callback will perform generic initialization and then
272 // call broker_sandboxer_callback.
273 CHECK(broker_process_
->Init(base::Bind(&UpdateProcessTypeAndEnableSandbox
,
274 broker_sandboxer_allocator
)));
277 } // namespace content