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 // Allow *kill from the GPU process temporarily until fork()
190 if (SyscallSets::IsKill(sysno
))
191 return ErrorCode(ErrorCode::ERR_ALLOWED
);
192 if (SyscallSets::IsEventFd(sysno
))
193 return ErrorCode(ErrorCode::ERR_ALLOWED
);
195 // Default on the baseline policy.
196 return SandboxBPFBasePolicy::EvaluateSyscall(sandbox
, sysno
);
200 bool GpuProcessPolicy::PreSandboxHook() {
201 // Warm up resources needed by the policy we're about to enable and
202 // eventually start a broker process.
203 const bool chromeos_arm_gpu
= IsChromeOS() && IsArchitectureArm();
204 // This policy is for x86 or Desktop.
205 DCHECK(!chromeos_arm_gpu
);
207 DCHECK(!broker_process());
208 // Create a new broker process.
209 InitGpuBrokerProcess(
210 GpuBrokerProcessPolicy::Create
,
211 std::vector
<std::string
>(), // No extra files in whitelist.
212 std::vector
<std::string
>());
214 if (IsArchitectureX86_64() || IsArchitectureI386()) {
215 // Accelerated video decode dlopen()'s some shared objects
216 // inside the sandbox, so preload them now.
217 if (IsAcceleratedVideoDecodeEnabled()) {
218 const char* I965DrvVideoPath
= NULL
;
220 if (IsArchitectureX86_64()) {
221 I965DrvVideoPath
= "/usr/lib64/va/drivers/i965_drv_video.so";
222 } else if (IsArchitectureI386()) {
223 I965DrvVideoPath
= "/usr/lib/va/drivers/i965_drv_video.so";
226 dlopen(I965DrvVideoPath
, RTLD_NOW
|RTLD_GLOBAL
|RTLD_NODELETE
);
227 dlopen("libva.so.1", RTLD_NOW
|RTLD_GLOBAL
|RTLD_NODELETE
);
228 dlopen("libva-x11.so.1", RTLD_NOW
|RTLD_GLOBAL
|RTLD_NODELETE
);
235 void GpuProcessPolicy::InitGpuBrokerProcess(
236 sandbox::SandboxBPFPolicy
* (*broker_sandboxer_allocator
)(void),
237 const std::vector
<std::string
>& read_whitelist_extra
,
238 const std::vector
<std::string
>& write_whitelist_extra
) {
239 static const char kDriRcPath
[] = "/etc/drirc";
240 static const char kDriCard0Path
[] = "/dev/dri/card0";
242 CHECK(broker_process_
== NULL
);
244 // All GPU process policies need these files brokered out.
245 std::vector
<std::string
> read_whitelist
;
246 read_whitelist
.push_back(kDriCard0Path
);
247 read_whitelist
.push_back(kDriRcPath
);
248 // Add eventual extra files from read_whitelist_extra.
249 read_whitelist
.insert(read_whitelist
.end(),
250 read_whitelist_extra
.begin(),
251 read_whitelist_extra
.end());
253 std::vector
<std::string
> write_whitelist
;
254 write_whitelist
.push_back(kDriCard0Path
);
255 // Add eventual extra files from write_whitelist_extra.
256 write_whitelist
.insert(write_whitelist
.end(),
257 write_whitelist_extra
.begin(),
258 write_whitelist_extra
.end());
260 broker_process_
= new BrokerProcess(GetFSDeniedErrno(),
263 // The initialization callback will perform generic initialization and then
264 // call broker_sandboxer_callback.
265 CHECK(broker_process_
->Init(base::Bind(&UpdateProcessTypeAndEnableSandbox
,
266 broker_sandboxer_allocator
)));
269 } // namespace content