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/bpf_dsl/bpf_dsl.h"
29 #include "sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.h"
30 #include "sandbox/linux/seccomp-bpf-helpers/syscall_sets.h"
31 #include "sandbox/linux/services/linux_syscalls.h"
32 #include "sandbox/linux/syscall_broker/broker_process.h"
34 using sandbox::syscall_broker::BrokerProcess
;
35 using sandbox::SyscallSets
;
36 using sandbox::arch_seccomp_data
;
37 using sandbox::bpf_dsl::Allow
;
38 using sandbox::bpf_dsl::ResultExpr
;
39 using sandbox::bpf_dsl::Trap
;
45 inline bool IsChromeOS() {
46 #if defined(OS_CHROMEOS)
53 inline bool IsArchitectureX86_64() {
54 #if defined(__x86_64__)
61 inline bool IsArchitectureI386() {
69 inline bool IsArchitectureArm() {
77 bool IsAcceleratedVideoEnabled() {
78 const base::CommandLine
& command_line
=
79 *base::CommandLine::ForCurrentProcess();
80 bool accelerated_encode_enabled
= false;
81 #if defined(OS_CHROMEOS)
82 accelerated_encode_enabled
=
83 !command_line
.HasSwitch(switches::kDisableVaapiAcceleratedVideoEncode
);
85 return !command_line
.HasSwitch(switches::kDisableAcceleratedVideoDecode
) ||
86 accelerated_encode_enabled
;
89 intptr_t GpuSIGSYS_Handler(const struct arch_seccomp_data
& args
,
90 void* aux_broker_process
) {
91 RAW_CHECK(aux_broker_process
);
92 BrokerProcess
* broker_process
=
93 static_cast<BrokerProcess
*>(aux_broker_process
);
96 return broker_process
->Access(reinterpret_cast<const char*>(args
.args
[0]),
97 static_cast<int>(args
.args
[1]));
99 #if defined(MEMORY_SANITIZER)
100 // http://crbug.com/372840
101 __msan_unpoison_string(reinterpret_cast<const char*>(args
.args
[0]));
103 return broker_process
->Open(reinterpret_cast<const char*>(args
.args
[0]),
104 static_cast<int>(args
.args
[1]));
106 // Allow using openat() as open().
107 if (static_cast<int>(args
.args
[0]) == AT_FDCWD
) {
109 broker_process
->Open(reinterpret_cast<const char*>(args
.args
[1]),
110 static_cast<int>(args
.args
[2]));
120 class GpuBrokerProcessPolicy
: public GpuProcessPolicy
{
122 static sandbox::bpf_dsl::Policy
* Create() {
123 return new GpuBrokerProcessPolicy();
125 ~GpuBrokerProcessPolicy() override
{}
127 ResultExpr
EvaluateSyscall(int system_call_number
) const override
;
130 GpuBrokerProcessPolicy() {}
131 DISALLOW_COPY_AND_ASSIGN(GpuBrokerProcessPolicy
);
134 // x86_64/i386 or desktop ARM.
135 // A GPU broker policy is the same as a GPU policy with open and
137 ResultExpr
GpuBrokerProcessPolicy::EvaluateSyscall(int sysno
) const {
144 return GpuProcessPolicy::EvaluateSyscall(sysno
);
148 void UpdateProcessTypeToGpuBroker() {
149 base::CommandLine::StringVector exec
=
150 base::CommandLine::ForCurrentProcess()->GetArgs();
151 base::CommandLine::Reset();
152 base::CommandLine::Init(0, NULL
);
153 base::CommandLine::ForCurrentProcess()->InitFromArgv(exec
);
154 base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
155 switches::kProcessType
, "gpu-broker");
157 // Update the process title. The argv was already cached by the call to
158 // SetProcessTitleFromCommandLine in content_main_runner.cc, so we can pass
159 // NULL here (we don't have the original argv at this point).
160 SetProcessTitleFromCommandLine(NULL
);
163 bool UpdateProcessTypeAndEnableSandbox(
164 sandbox::bpf_dsl::Policy
* (*broker_sandboxer_allocator
)(void)) {
165 DCHECK(broker_sandboxer_allocator
);
166 UpdateProcessTypeToGpuBroker();
167 return SandboxSeccompBPF::StartSandboxWithExternalPolicy(
168 make_scoped_ptr(broker_sandboxer_allocator()));
173 GpuProcessPolicy::GpuProcessPolicy() : GpuProcessPolicy(false) {
176 GpuProcessPolicy::GpuProcessPolicy(bool allow_mincore
)
177 : broker_process_(NULL
), allow_mincore_(allow_mincore
) {
180 GpuProcessPolicy::~GpuProcessPolicy() {}
182 // Main policy for x86_64/i386. Extended by CrosArmGpuProcessPolicy.
183 ResultExpr
GpuProcessPolicy::EvaluateSyscall(int sysno
) const {
188 if (allow_mincore_
) {
191 return SandboxBPFBasePolicy::EvaluateSyscall(sysno
);
193 #if defined(__i386__) || defined(__x86_64__) || defined(__mips__)
194 // The Nvidia driver uses flags not in the baseline policy
195 // (MAP_LOCKED | MAP_EXECUTABLE | MAP_32BIT)
198 // We also hit this on the linux_chromeos bot but don't yet know what
199 // weird flags were involved.
201 // TODO(jln): restrict prctl.
207 DCHECK(broker_process_
);
208 return Trap(GpuSIGSYS_Handler
, broker_process_
);
209 case __NR_setpriority
:
210 return sandbox::RestrictGetSetpriority(GetPolicyPid());
211 case __NR_sched_getaffinity
:
212 case __NR_sched_setaffinity
:
213 return sandbox::RestrictSchedTarget(GetPolicyPid(), sysno
);
215 if (SyscallSets::IsEventFd(sysno
))
218 // Default on the baseline policy.
219 return SandboxBPFBasePolicy::EvaluateSyscall(sysno
);
223 bool GpuProcessPolicy::PreSandboxHook() {
224 // Warm up resources needed by the policy we're about to enable and
225 // eventually start a broker process.
226 const bool chromeos_arm_gpu
= IsChromeOS() && IsArchitectureArm();
227 // This policy is for x86 or Desktop.
228 DCHECK(!chromeos_arm_gpu
);
230 DCHECK(!broker_process());
231 // Create a new broker process.
232 InitGpuBrokerProcess(
233 GpuBrokerProcessPolicy::Create
,
234 std::vector
<std::string
>(), // No extra files in whitelist.
235 std::vector
<std::string
>());
237 if (IsArchitectureX86_64() || IsArchitectureI386()) {
238 // Accelerated video dlopen()'s some shared objects
239 // inside the sandbox, so preload them now.
240 if (IsAcceleratedVideoEnabled()) {
241 const char* I965DrvVideoPath
= NULL
;
243 if (IsArchitectureX86_64()) {
244 I965DrvVideoPath
= "/usr/lib64/va/drivers/i965_drv_video.so";
245 } else if (IsArchitectureI386()) {
246 I965DrvVideoPath
= "/usr/lib/va/drivers/i965_drv_video.so";
249 dlopen(I965DrvVideoPath
, RTLD_NOW
|RTLD_GLOBAL
|RTLD_NODELETE
);
250 dlopen("libva.so.1", RTLD_NOW
|RTLD_GLOBAL
|RTLD_NODELETE
);
251 dlopen("libva-x11.so.1", RTLD_NOW
|RTLD_GLOBAL
|RTLD_NODELETE
);
258 void GpuProcessPolicy::InitGpuBrokerProcess(
259 sandbox::bpf_dsl::Policy
* (*broker_sandboxer_allocator
)(void),
260 const std::vector
<std::string
>& read_whitelist_extra
,
261 const std::vector
<std::string
>& write_whitelist_extra
) {
262 static const char kDriRcPath
[] = "/etc/drirc";
263 static const char kDriCard0Path
[] = "/dev/dri/card0";
265 CHECK(broker_process_
== NULL
);
267 // All GPU process policies need these files brokered out.
268 std::vector
<std::string
> read_whitelist
;
269 read_whitelist
.push_back(kDriCard0Path
);
270 read_whitelist
.push_back(kDriRcPath
);
271 // Add eventual extra files from read_whitelist_extra.
272 read_whitelist
.insert(read_whitelist
.end(),
273 read_whitelist_extra
.begin(),
274 read_whitelist_extra
.end());
276 std::vector
<std::string
> write_whitelist
;
277 write_whitelist
.push_back(kDriCard0Path
);
278 // Add eventual extra files from write_whitelist_extra.
279 write_whitelist
.insert(write_whitelist
.end(),
280 write_whitelist_extra
.begin(),
281 write_whitelist_extra
.end());
283 broker_process_
= new BrokerProcess(GetFSDeniedErrno(),
286 // The initialization callback will perform generic initialization and then
287 // call broker_sandboxer_callback.
288 CHECK(broker_process_
->Init(base::Bind(&UpdateProcessTypeAndEnableSandbox
,
289 broker_sandboxer_allocator
)));
292 } // namespace content