Fix crash with --use-gl=egl on Linux.
[chromium-blink-merge.git] / content / common / sandbox_linux / sandbox_seccomp_bpf_linux.cc
blob4c871d953e75ffd6233b56b755e507ff9f1c3f33
1 // Copyright (c) 2012 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/sandbox_seccomp_bpf_linux.h"
7 #include <errno.h>
8 #include <fcntl.h>
9 #include <sys/socket.h>
10 #include <sys/stat.h>
11 #include <sys/types.h>
13 #include "base/basictypes.h"
14 #include "base/command_line.h"
15 #include "base/logging.h"
16 #include "build/build_config.h"
17 #include "content/public/common/content_switches.h"
18 #include "sandbox/linux/bpf_dsl/bpf_dsl.h"
20 #if defined(USE_SECCOMP_BPF)
22 #include "base/posix/eintr_wrapper.h"
23 #include "content/common/sandbox_linux/bpf_cros_arm_gpu_policy_linux.h"
24 #include "content/common/sandbox_linux/bpf_gpu_policy_linux.h"
25 #include "content/common/sandbox_linux/bpf_ppapi_policy_linux.h"
26 #include "content/common/sandbox_linux/bpf_renderer_policy_linux.h"
27 #include "content/common/sandbox_linux/bpf_utility_policy_linux.h"
28 #include "content/common/sandbox_linux/sandbox_bpf_base_policy_linux.h"
29 #include "content/common/sandbox_linux/sandbox_linux.h"
30 #include "sandbox/linux/seccomp-bpf-helpers/baseline_policy.h"
31 #include "sandbox/linux/seccomp-bpf-helpers/sigsys_handlers.h"
32 #include "sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.h"
33 #include "sandbox/linux/seccomp-bpf-helpers/syscall_sets.h"
34 #include "sandbox/linux/seccomp-bpf/sandbox_bpf.h"
35 #include "sandbox/linux/services/linux_syscalls.h"
37 #if !defined(IN_NACL_HELPER)
38 #include "ui/gl/gl_switches.h"
39 #endif
41 using sandbox::BaselinePolicy;
42 using sandbox::SandboxBPF;
43 using sandbox::SyscallSets;
44 using sandbox::bpf_dsl::Allow;
45 using sandbox::bpf_dsl::ResultExpr;
47 #else
49 // Make sure that seccomp-bpf does not get disabled by mistake. Also make sure
50 // that we think twice about this when adding a new architecture.
51 #if !defined(ARCH_CPU_ARM64)
52 #error "Seccomp-bpf disabled on supported architecture!"
53 #endif // !defined(ARCH_CPU_ARM64)
55 #endif //
57 namespace content {
59 #if defined(USE_SECCOMP_BPF)
60 namespace {
62 void StartSandboxWithPolicy(sandbox::bpf_dsl::SandboxBPFDSLPolicy* policy);
64 inline bool IsChromeOS() {
65 #if defined(OS_CHROMEOS)
66 return true;
67 #else
68 return false;
69 #endif
72 inline bool IsArchitectureArm() {
73 #if defined(__arm__)
74 return true;
75 #else
76 return false;
77 #endif
80 class BlacklistDebugAndNumaPolicy : public SandboxBPFBasePolicy {
81 public:
82 BlacklistDebugAndNumaPolicy() {}
83 virtual ~BlacklistDebugAndNumaPolicy() {}
85 virtual ResultExpr EvaluateSyscall(int system_call_number) const override;
87 private:
88 DISALLOW_COPY_AND_ASSIGN(BlacklistDebugAndNumaPolicy);
91 ResultExpr BlacklistDebugAndNumaPolicy::EvaluateSyscall(int sysno) const {
92 if (SyscallSets::IsDebug(sysno) || SyscallSets::IsNuma(sysno))
93 return sandbox::CrashSIGSYS();
95 return Allow();
98 class AllowAllPolicy : public SandboxBPFBasePolicy {
99 public:
100 AllowAllPolicy() {}
101 virtual ~AllowAllPolicy() {}
103 virtual ResultExpr EvaluateSyscall(int system_call_number) const override;
105 private:
106 DISALLOW_COPY_AND_ASSIGN(AllowAllPolicy);
109 // Allow all syscalls.
110 // This will still deny x32 or IA32 calls in 64 bits mode or
111 // 64 bits system calls in compatibility mode.
112 ResultExpr AllowAllPolicy::EvaluateSyscall(int sysno) const {
113 return Allow();
116 // If a BPF policy is engaged for |process_type|, run a few sanity checks.
117 void RunSandboxSanityChecks(const std::string& process_type) {
118 if (process_type == switches::kRendererProcess ||
119 process_type == switches::kGpuProcess ||
120 process_type == switches::kPpapiPluginProcess) {
121 int syscall_ret;
122 errno = 0;
124 // Without the sandbox, this would EBADF.
125 syscall_ret = fchmod(-1, 07777);
126 CHECK_EQ(-1, syscall_ret);
127 CHECK_EQ(EPERM, errno);
129 // Run most of the sanity checks only in DEBUG mode to avoid a perf.
130 // impact.
131 #if !defined(NDEBUG)
132 // open() must be restricted.
133 syscall_ret = open("/etc/passwd", O_RDONLY);
134 CHECK_EQ(-1, syscall_ret);
135 CHECK_EQ(SandboxBPFBasePolicy::GetFSDeniedErrno(), errno);
137 // We should never allow the creation of netlink sockets.
138 syscall_ret = socket(AF_NETLINK, SOCK_DGRAM, 0);
139 CHECK_EQ(-1, syscall_ret);
140 CHECK_EQ(EPERM, errno);
141 #endif // !defined(NDEBUG)
146 // This function takes ownership of |policy|.
147 void StartSandboxWithPolicy(sandbox::bpf_dsl::SandboxBPFDSLPolicy* policy) {
148 // Starting the sandbox is a one-way operation. The kernel doesn't allow
149 // us to unload a sandbox policy after it has been started. Nonetheless,
150 // in order to make the use of the "Sandbox" object easier, we allow for
151 // the object to be destroyed after the sandbox has been started. Note that
152 // doing so does not stop the sandbox.
153 SandboxBPF sandbox;
154 sandbox.SetSandboxPolicy(policy);
155 CHECK(sandbox.StartSandbox(SandboxBPF::PROCESS_SINGLE_THREADED));
158 // nacl_helper needs to be tiny and includes only part of content/
159 // in its dependencies. Make sure to not link things that are not needed.
160 #if !defined(IN_NACL_HELPER)
161 scoped_ptr<SandboxBPFBasePolicy> GetGpuProcessSandbox() {
162 const base::CommandLine& command_line =
163 *base::CommandLine::ForCurrentProcess();
164 bool allow_sysv_shm = false;
165 if (command_line.HasSwitch(switches::kGpuSandboxAllowSysVShm)) {
166 DCHECK(IsArchitectureArm());
167 allow_sysv_shm = true;
170 if (IsChromeOS() && IsArchitectureArm()) {
171 return scoped_ptr<SandboxBPFBasePolicy>(
172 new CrosArmGpuProcessPolicy(allow_sysv_shm));
173 } else {
174 bool allow_mincore = command_line.HasSwitch(switches::kUseGL) &&
175 command_line.GetSwitchValueASCII(switches::kUseGL) ==
176 gfx::kGLImplementationEGLName;
177 return scoped_ptr<SandboxBPFBasePolicy>(
178 new GpuProcessPolicy(allow_mincore));
182 // Initialize the seccomp-bpf sandbox.
183 bool StartBPFSandbox(const base::CommandLine& command_line,
184 const std::string& process_type) {
185 scoped_ptr<SandboxBPFBasePolicy> policy;
187 if (process_type == switches::kGpuProcess) {
188 policy.reset(GetGpuProcessSandbox().release());
189 } else if (process_type == switches::kRendererProcess) {
190 policy.reset(new RendererProcessPolicy);
191 } else if (process_type == switches::kPpapiPluginProcess) {
192 policy.reset(new PpapiProcessPolicy);
193 } else if (process_type == switches::kUtilityProcess) {
194 policy.reset(new UtilityProcessPolicy);
195 } else {
196 NOTREACHED();
197 policy.reset(new AllowAllPolicy);
200 CHECK(policy->PreSandboxHook());
201 StartSandboxWithPolicy(policy.release());
203 RunSandboxSanityChecks(process_type);
204 return true;
206 #else // defined(IN_NACL_HELPER)
207 bool StartBPFSandbox(const base::CommandLine& command_line,
208 const std::string& process_type) {
209 NOTREACHED();
210 // Avoid -Wunused-function with no-op code.
211 ignore_result(IsChromeOS);
212 ignore_result(IsArchitectureArm);
213 ignore_result(RunSandboxSanityChecks);
214 return false;
216 #endif // !defined(IN_NACL_HELPER)
218 } // namespace
220 #endif // USE_SECCOMP_BPF
222 // Is seccomp BPF globally enabled?
223 bool SandboxSeccompBPF::IsSeccompBPFDesired() {
224 const base::CommandLine& command_line =
225 *base::CommandLine::ForCurrentProcess();
226 if (!command_line.HasSwitch(switches::kNoSandbox) &&
227 !command_line.HasSwitch(switches::kDisableSeccompFilterSandbox)) {
228 return true;
229 } else {
230 return false;
234 bool SandboxSeccompBPF::ShouldEnableSeccompBPF(
235 const std::string& process_type) {
236 #if defined(USE_SECCOMP_BPF)
237 const base::CommandLine& command_line =
238 *base::CommandLine::ForCurrentProcess();
239 if (process_type == switches::kGpuProcess)
240 return !command_line.HasSwitch(switches::kDisableGpuSandbox);
242 return true;
243 #endif // USE_SECCOMP_BPF
244 return false;
247 bool SandboxSeccompBPF::SupportsSandbox() {
248 #if defined(USE_SECCOMP_BPF)
249 // TODO(jln): pass the saved proc_fd_ from the LinuxSandbox singleton
250 // here.
251 SandboxBPF::SandboxStatus bpf_sandbox_status =
252 SandboxBPF::SupportsSeccompSandbox(-1);
253 // Kernel support is what we are interested in here. Other status
254 // such as STATUS_UNAVAILABLE (has threads) still indicate kernel support.
255 // We make this a negative check, since if there is a bug, we would rather
256 // "fail closed" (expect a sandbox to be available and try to start it).
257 if (bpf_sandbox_status != SandboxBPF::STATUS_UNSUPPORTED) {
258 return true;
260 #endif
261 return false;
264 bool SandboxSeccompBPF::StartSandbox(const std::string& process_type) {
265 #if defined(USE_SECCOMP_BPF)
266 const base::CommandLine& command_line =
267 *base::CommandLine::ForCurrentProcess();
269 if (IsSeccompBPFDesired() && // Global switches policy.
270 ShouldEnableSeccompBPF(process_type) && // Process-specific policy.
271 SupportsSandbox()) {
272 // If the kernel supports the sandbox, and if the command line says we
273 // should enable it, enable it or die.
274 bool started_sandbox = StartBPFSandbox(command_line, process_type);
275 CHECK(started_sandbox);
276 return true;
278 #endif
279 return false;
282 bool SandboxSeccompBPF::StartSandboxWithExternalPolicy(
283 scoped_ptr<sandbox::bpf_dsl::SandboxBPFDSLPolicy> policy) {
284 #if defined(USE_SECCOMP_BPF)
285 if (IsSeccompBPFDesired() && SupportsSandbox()) {
286 CHECK(policy);
287 StartSandboxWithPolicy(policy.release());
288 return true;
290 #endif // defined(USE_SECCOMP_BPF)
291 return false;
294 scoped_ptr<sandbox::bpf_dsl::SandboxBPFDSLPolicy>
295 SandboxSeccompBPF::GetBaselinePolicy() {
296 #if defined(USE_SECCOMP_BPF)
297 return scoped_ptr<sandbox::bpf_dsl::SandboxBPFDSLPolicy>(new BaselinePolicy);
298 #else
299 return scoped_ptr<sandbox::bpf_dsl::SandboxBPFDSLPolicy>();
300 #endif // defined(USE_SECCOMP_BPF)
303 } // namespace content