We started redesigning GpuMemoryBuffer interface to handle multiple buffers [0].
[chromium-blink-merge.git] / content / common / sandbox_linux / sandbox_seccomp_bpf_linux.cc
blob2f24b62719e60f32662ae1f095ccf1705a0446b2
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/files/scoped_file.h"
23 #include "base/memory/scoped_ptr.h"
24 #include "base/posix/eintr_wrapper.h"
25 #include "content/common/sandbox_linux/bpf_cros_arm_gpu_policy_linux.h"
26 #include "content/common/sandbox_linux/bpf_gpu_policy_linux.h"
27 #include "content/common/sandbox_linux/bpf_ppapi_policy_linux.h"
28 #include "content/common/sandbox_linux/bpf_renderer_policy_linux.h"
29 #include "content/common/sandbox_linux/bpf_utility_policy_linux.h"
30 #include "content/common/sandbox_linux/sandbox_bpf_base_policy_linux.h"
31 #include "content/common/sandbox_linux/sandbox_linux.h"
32 #include "sandbox/linux/seccomp-bpf-helpers/baseline_policy.h"
33 #include "sandbox/linux/seccomp-bpf-helpers/sigsys_handlers.h"
34 #include "sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.h"
35 #include "sandbox/linux/seccomp-bpf-helpers/syscall_sets.h"
36 #include "sandbox/linux/seccomp-bpf/sandbox_bpf.h"
37 #include "sandbox/linux/system_headers/linux_syscalls.h"
39 #if !defined(IN_NACL_HELPER)
40 #include "ui/gl/gl_switches.h"
41 #endif
43 using sandbox::BaselinePolicy;
44 using sandbox::SandboxBPF;
45 using sandbox::SyscallSets;
46 using sandbox::bpf_dsl::Allow;
47 using sandbox::bpf_dsl::ResultExpr;
49 #else
51 // Make sure that seccomp-bpf does not get disabled by mistake. Also make sure
52 // that we think twice about this when adding a new architecture.
53 #if !defined(ARCH_CPU_ARM64)
54 #error "Seccomp-bpf disabled on supported architecture!"
55 #endif // !defined(ARCH_CPU_ARM64)
57 #endif //
59 namespace content {
61 #if defined(USE_SECCOMP_BPF)
62 namespace {
64 void StartSandboxWithPolicy(sandbox::bpf_dsl::Policy* policy,
65 base::ScopedFD proc_fd);
67 inline bool IsChromeOS() {
68 #if defined(OS_CHROMEOS)
69 return true;
70 #else
71 return false;
72 #endif
75 inline bool IsArchitectureArm() {
76 #if defined(__arm__)
77 return true;
78 #else
79 return false;
80 #endif
83 class BlacklistDebugAndNumaPolicy : public SandboxBPFBasePolicy {
84 public:
85 BlacklistDebugAndNumaPolicy() {}
86 ~BlacklistDebugAndNumaPolicy() override {}
88 ResultExpr EvaluateSyscall(int system_call_number) const override;
90 private:
91 DISALLOW_COPY_AND_ASSIGN(BlacklistDebugAndNumaPolicy);
94 ResultExpr BlacklistDebugAndNumaPolicy::EvaluateSyscall(int sysno) const {
95 if (SyscallSets::IsDebug(sysno) || SyscallSets::IsNuma(sysno))
96 return sandbox::CrashSIGSYS();
98 return Allow();
101 class AllowAllPolicy : public SandboxBPFBasePolicy {
102 public:
103 AllowAllPolicy() {}
104 ~AllowAllPolicy() override {}
106 ResultExpr EvaluateSyscall(int system_call_number) const override;
108 private:
109 DISALLOW_COPY_AND_ASSIGN(AllowAllPolicy);
112 // Allow all syscalls.
113 // This will still deny x32 or IA32 calls in 64 bits mode or
114 // 64 bits system calls in compatibility mode.
115 ResultExpr AllowAllPolicy::EvaluateSyscall(int sysno) const {
116 return Allow();
119 // If a BPF policy is engaged for |process_type|, run a few sanity checks.
120 void RunSandboxSanityChecks(const std::string& process_type) {
121 if (process_type == switches::kRendererProcess ||
122 process_type == switches::kGpuProcess ||
123 process_type == switches::kPpapiPluginProcess) {
124 int syscall_ret;
125 errno = 0;
127 // Without the sandbox, this would EBADF.
128 syscall_ret = fchmod(-1, 07777);
129 CHECK_EQ(-1, syscall_ret);
130 CHECK_EQ(EPERM, errno);
132 // Run most of the sanity checks only in DEBUG mode to avoid a perf.
133 // impact.
134 #if !defined(NDEBUG)
135 // open() must be restricted.
136 syscall_ret = open("/etc/passwd", O_RDONLY);
137 CHECK_EQ(-1, syscall_ret);
138 CHECK_EQ(SandboxBPFBasePolicy::GetFSDeniedErrno(), errno);
140 // We should never allow the creation of netlink sockets.
141 syscall_ret = socket(AF_NETLINK, SOCK_DGRAM, 0);
142 CHECK_EQ(-1, syscall_ret);
143 CHECK_EQ(EPERM, errno);
144 #endif // !defined(NDEBUG)
149 // This function takes ownership of |policy|.
150 void StartSandboxWithPolicy(sandbox::bpf_dsl::Policy* policy,
151 base::ScopedFD proc_fd) {
152 // Starting the sandbox is a one-way operation. The kernel doesn't allow
153 // us to unload a sandbox policy after it has been started. Nonetheless,
154 // in order to make the use of the "Sandbox" object easier, we allow for
155 // the object to be destroyed after the sandbox has been started. Note that
156 // doing so does not stop the sandbox.
157 SandboxBPF sandbox(policy);
159 sandbox.SetProcFd(proc_fd.Pass());
160 CHECK(sandbox.StartSandbox(SandboxBPF::SeccompLevel::SINGLE_THREADED));
163 // nacl_helper needs to be tiny and includes only part of content/
164 // in its dependencies. Make sure to not link things that are not needed.
165 #if !defined(IN_NACL_HELPER)
166 scoped_ptr<SandboxBPFBasePolicy> GetGpuProcessSandbox() {
167 const base::CommandLine& command_line =
168 *base::CommandLine::ForCurrentProcess();
169 bool allow_sysv_shm = false;
170 if (command_line.HasSwitch(switches::kGpuSandboxAllowSysVShm)) {
171 DCHECK(IsArchitectureArm());
172 allow_sysv_shm = true;
175 if (IsChromeOS() && IsArchitectureArm()) {
176 return scoped_ptr<SandboxBPFBasePolicy>(
177 new CrosArmGpuProcessPolicy(allow_sysv_shm));
178 } else {
179 bool allow_mincore = command_line.HasSwitch(switches::kUseGL) &&
180 command_line.GetSwitchValueASCII(switches::kUseGL) ==
181 gfx::kGLImplementationEGLName;
182 return scoped_ptr<SandboxBPFBasePolicy>(
183 new GpuProcessPolicy(allow_mincore));
187 // Initialize the seccomp-bpf sandbox.
188 bool StartBPFSandbox(const base::CommandLine& command_line,
189 const std::string& process_type,
190 base::ScopedFD proc_fd) {
191 scoped_ptr<SandboxBPFBasePolicy> policy;
193 if (process_type == switches::kGpuProcess) {
194 policy.reset(GetGpuProcessSandbox().release());
195 } else if (process_type == switches::kRendererProcess) {
196 policy.reset(new RendererProcessPolicy);
197 } else if (process_type == switches::kPpapiPluginProcess) {
198 policy.reset(new PpapiProcessPolicy);
199 } else if (process_type == switches::kUtilityProcess) {
200 policy.reset(new UtilityProcessPolicy);
201 } else {
202 NOTREACHED();
203 policy.reset(new AllowAllPolicy);
206 CHECK(policy->PreSandboxHook());
207 StartSandboxWithPolicy(policy.release(), proc_fd.Pass());
209 RunSandboxSanityChecks(process_type);
210 return true;
212 #else // defined(IN_NACL_HELPER)
213 bool StartBPFSandbox(const base::CommandLine& command_line,
214 const std::string& process_type) {
215 NOTREACHED();
216 // Avoid -Wunused-function with no-op code.
217 ignore_result(IsChromeOS);
218 ignore_result(IsArchitectureArm);
219 ignore_result(RunSandboxSanityChecks);
220 return false;
222 #endif // !defined(IN_NACL_HELPER)
224 } // namespace
226 #endif // USE_SECCOMP_BPF
228 // Is seccomp BPF globally enabled?
229 bool SandboxSeccompBPF::IsSeccompBPFDesired() {
230 const base::CommandLine& command_line =
231 *base::CommandLine::ForCurrentProcess();
232 if (!command_line.HasSwitch(switches::kNoSandbox) &&
233 !command_line.HasSwitch(switches::kDisableSeccompFilterSandbox)) {
234 return true;
235 } else {
236 return false;
240 bool SandboxSeccompBPF::ShouldEnableSeccompBPF(
241 const std::string& process_type) {
242 #if defined(USE_SECCOMP_BPF)
243 const base::CommandLine& command_line =
244 *base::CommandLine::ForCurrentProcess();
245 if (process_type == switches::kGpuProcess)
246 return !command_line.HasSwitch(switches::kDisableGpuSandbox);
248 return true;
249 #endif // USE_SECCOMP_BPF
250 return false;
253 bool SandboxSeccompBPF::SupportsSandbox() {
254 #if defined(USE_SECCOMP_BPF)
255 return SandboxBPF::SupportsSeccompSandbox(
256 SandboxBPF::SeccompLevel::SINGLE_THREADED);
257 #endif
258 return false;
261 bool SandboxSeccompBPF::SupportsSandboxWithTsync() {
262 #if defined(USE_SECCOMP_BPF)
263 return SandboxBPF::SupportsSeccompSandbox(
264 SandboxBPF::SeccompLevel::MULTI_THREADED);
265 #endif
266 return false;
269 bool SandboxSeccompBPF::StartSandbox(const std::string& process_type,
270 base::ScopedFD proc_fd) {
271 #if defined(USE_SECCOMP_BPF)
272 const base::CommandLine& command_line =
273 *base::CommandLine::ForCurrentProcess();
275 if (IsSeccompBPFDesired() && // Global switches policy.
276 ShouldEnableSeccompBPF(process_type) && // Process-specific policy.
277 SupportsSandbox()) {
278 // If the kernel supports the sandbox, and if the command line says we
279 // should enable it, enable it or die.
280 bool started_sandbox =
281 StartBPFSandbox(command_line, process_type, proc_fd.Pass());
282 CHECK(started_sandbox);
283 return true;
285 #endif
286 return false;
289 bool SandboxSeccompBPF::StartSandboxWithExternalPolicy(
290 scoped_ptr<sandbox::bpf_dsl::Policy> policy,
291 base::ScopedFD proc_fd) {
292 #if defined(USE_SECCOMP_BPF)
293 if (IsSeccompBPFDesired() && SupportsSandbox()) {
294 CHECK(policy);
295 StartSandboxWithPolicy(policy.release(), proc_fd.Pass());
296 return true;
298 #endif // defined(USE_SECCOMP_BPF)
299 return false;
302 scoped_ptr<sandbox::bpf_dsl::Policy> SandboxSeccompBPF::GetBaselinePolicy() {
303 #if defined(USE_SECCOMP_BPF)
304 return scoped_ptr<sandbox::bpf_dsl::Policy>(new BaselinePolicy);
305 #else
306 return scoped_ptr<sandbox::bpf_dsl::Policy>();
307 #endif // defined(USE_SECCOMP_BPF)
310 } // namespace content