Updating trunk VERSION from 2139.0 to 2140.0
[chromium-blink-merge.git] / content / common / sandbox_linux / sandbox_seccomp_bpf_linux.cc
blob86d2c0fc60c78a0f71c6d04c920cddec0a3d3853
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/stat.h>
12 #include <sys/types.h>
13 #include <sys/types.h>
15 #include "base/basictypes.h"
16 #include "base/command_line.h"
17 #include "base/logging.h"
18 #include "build/build_config.h"
19 #include "content/public/common/content_switches.h"
20 #include "sandbox/linux/seccomp-bpf/sandbox_bpf_policy.h"
22 #if defined(USE_SECCOMP_BPF)
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/services/linux_syscalls.h"
39 using sandbox::BaselinePolicy;
40 using sandbox::SandboxBPF;
41 using sandbox::SyscallSets;
42 using sandbox::bpf_dsl::Allow;
43 using sandbox::bpf_dsl::ResultExpr;
45 #else
47 // Make sure that seccomp-bpf does not get disabled by mistake. Also make sure
48 // that we think twice about this when adding a new architecture.
49 #if !defined(ARCH_CPU_ARM64)
50 #error "Seccomp-bpf disabled on supported architecture!"
51 #endif // !defined(ARCH_CPU_ARM64)
53 #endif //
55 namespace content {
57 #if defined(USE_SECCOMP_BPF)
58 namespace {
60 void StartSandboxWithPolicy(sandbox::SandboxBPFPolicy* policy);
62 inline bool IsChromeOS() {
63 #if defined(OS_CHROMEOS)
64 return true;
65 #else
66 return false;
67 #endif
70 inline bool IsArchitectureArm() {
71 #if defined(__arm__)
72 return true;
73 #else
74 return false;
75 #endif
78 class BlacklistDebugAndNumaPolicy : public SandboxBPFBasePolicy {
79 public:
80 BlacklistDebugAndNumaPolicy() {}
81 virtual ~BlacklistDebugAndNumaPolicy() {}
83 virtual ResultExpr EvaluateSyscall(int system_call_number) const OVERRIDE;
85 private:
86 DISALLOW_COPY_AND_ASSIGN(BlacklistDebugAndNumaPolicy);
89 ResultExpr BlacklistDebugAndNumaPolicy::EvaluateSyscall(int sysno) const {
90 if (SyscallSets::IsDebug(sysno) || SyscallSets::IsNuma(sysno))
91 return sandbox::CrashSIGSYS();
93 return Allow();
96 class AllowAllPolicy : public SandboxBPFBasePolicy {
97 public:
98 AllowAllPolicy() {}
99 virtual ~AllowAllPolicy() {}
101 virtual ResultExpr EvaluateSyscall(int system_call_number) const OVERRIDE;
103 private:
104 DISALLOW_COPY_AND_ASSIGN(AllowAllPolicy);
107 // Allow all syscalls.
108 // This will still deny x32 or IA32 calls in 64 bits mode or
109 // 64 bits system calls in compatibility mode.
110 ResultExpr AllowAllPolicy::EvaluateSyscall(int sysno) const {
111 return Allow();
114 // If a BPF policy is engaged for |process_type|, run a few sanity checks.
115 void RunSandboxSanityChecks(const std::string& process_type) {
116 if (process_type == switches::kRendererProcess ||
117 process_type == switches::kGpuProcess ||
118 process_type == switches::kPpapiPluginProcess) {
119 int syscall_ret;
120 errno = 0;
122 // Without the sandbox, this would EBADF.
123 syscall_ret = fchmod(-1, 07777);
124 CHECK_EQ(-1, syscall_ret);
125 CHECK_EQ(EPERM, errno);
127 // Run most of the sanity checks only in DEBUG mode to avoid a perf.
128 // impact.
129 #if !defined(NDEBUG)
130 // open() must be restricted.
131 syscall_ret = open("/etc/passwd", O_RDONLY);
132 CHECK_EQ(-1, syscall_ret);
133 CHECK_EQ(SandboxBPFBasePolicy::GetFSDeniedErrno(), errno);
135 // We should never allow the creation of netlink sockets.
136 syscall_ret = socket(AF_NETLINK, SOCK_DGRAM, 0);
137 CHECK_EQ(-1, syscall_ret);
138 CHECK_EQ(EPERM, errno);
139 #endif // !defined(NDEBUG)
144 // This function takes ownership of |policy|.
145 void StartSandboxWithPolicy(sandbox::SandboxBPFPolicy* policy) {
146 // Starting the sandbox is a one-way operation. The kernel doesn't allow
147 // us to unload a sandbox policy after it has been started. Nonetheless,
148 // in order to make the use of the "Sandbox" object easier, we allow for
149 // the object to be destroyed after the sandbox has been started. Note that
150 // doing so does not stop the sandbox.
151 SandboxBPF sandbox;
152 sandbox.SetSandboxPolicy(policy);
153 CHECK(sandbox.StartSandbox(SandboxBPF::PROCESS_SINGLE_THREADED));
156 // nacl_helper needs to be tiny and includes only part of content/
157 // in its dependencies. Make sure to not link things that are not needed.
158 #if !defined(IN_NACL_HELPER)
159 scoped_ptr<SandboxBPFBasePolicy> GetGpuProcessSandbox() {
160 const base::CommandLine& command_line =
161 *base::CommandLine::ForCurrentProcess();
162 bool allow_sysv_shm = false;
163 if (command_line.HasSwitch(switches::kGpuSandboxAllowSysVShm)) {
164 DCHECK(IsArchitectureArm());
165 allow_sysv_shm = true;
168 if (IsChromeOS() && IsArchitectureArm()) {
169 return scoped_ptr<SandboxBPFBasePolicy>(
170 new CrosArmGpuProcessPolicy(allow_sysv_shm));
171 } else {
172 return scoped_ptr<SandboxBPFBasePolicy>(new GpuProcessPolicy);
176 // Initialize the seccomp-bpf sandbox.
177 bool StartBPFSandbox(const base::CommandLine& command_line,
178 const std::string& process_type) {
179 scoped_ptr<SandboxBPFBasePolicy> policy;
181 if (process_type == switches::kGpuProcess) {
182 policy.reset(GetGpuProcessSandbox().release());
183 } else if (process_type == switches::kRendererProcess) {
184 policy.reset(new RendererProcessPolicy);
185 } else if (process_type == switches::kPpapiPluginProcess) {
186 policy.reset(new PpapiProcessPolicy);
187 } else if (process_type == switches::kUtilityProcess) {
188 policy.reset(new UtilityProcessPolicy);
189 } else {
190 NOTREACHED();
191 policy.reset(new AllowAllPolicy);
194 CHECK(policy->PreSandboxHook());
195 StartSandboxWithPolicy(policy.release());
197 RunSandboxSanityChecks(process_type);
198 return true;
200 #else // defined(IN_NACL_HELPER)
201 bool StartBPFSandbox(const base::CommandLine& command_line,
202 const std::string& process_type) {
203 NOTREACHED();
204 // Avoid -Wunused-function with no-op code.
205 ignore_result(IsChromeOS);
206 ignore_result(IsArchitectureArm);
207 ignore_result(RunSandboxSanityChecks);
208 return false;
210 #endif // !defined(IN_NACL_HELPER)
212 } // namespace
214 #endif // USE_SECCOMP_BPF
216 // Is seccomp BPF globally enabled?
217 bool SandboxSeccompBPF::IsSeccompBPFDesired() {
218 const base::CommandLine& command_line =
219 *base::CommandLine::ForCurrentProcess();
220 if (!command_line.HasSwitch(switches::kNoSandbox) &&
221 !command_line.HasSwitch(switches::kDisableSeccompFilterSandbox)) {
222 return true;
223 } else {
224 return false;
228 bool SandboxSeccompBPF::ShouldEnableSeccompBPF(
229 const std::string& process_type) {
230 #if defined(USE_SECCOMP_BPF)
231 const base::CommandLine& command_line =
232 *base::CommandLine::ForCurrentProcess();
233 if (process_type == switches::kGpuProcess)
234 return !command_line.HasSwitch(switches::kDisableGpuSandbox);
236 return true;
237 #endif // USE_SECCOMP_BPF
238 return false;
241 bool SandboxSeccompBPF::SupportsSandbox() {
242 #if defined(USE_SECCOMP_BPF)
243 // TODO(jln): pass the saved proc_fd_ from the LinuxSandbox singleton
244 // here.
245 SandboxBPF::SandboxStatus bpf_sandbox_status =
246 SandboxBPF::SupportsSeccompSandbox(-1);
247 // Kernel support is what we are interested in here. Other status
248 // such as STATUS_UNAVAILABLE (has threads) still indicate kernel support.
249 // We make this a negative check, since if there is a bug, we would rather
250 // "fail closed" (expect a sandbox to be available and try to start it).
251 if (bpf_sandbox_status != SandboxBPF::STATUS_UNSUPPORTED) {
252 return true;
254 #endif
255 return false;
258 bool SandboxSeccompBPF::StartSandbox(const std::string& process_type) {
259 #if defined(USE_SECCOMP_BPF)
260 const base::CommandLine& command_line =
261 *base::CommandLine::ForCurrentProcess();
263 if (IsSeccompBPFDesired() && // Global switches policy.
264 ShouldEnableSeccompBPF(process_type) && // Process-specific policy.
265 SupportsSandbox()) {
266 // If the kernel supports the sandbox, and if the command line says we
267 // should enable it, enable it or die.
268 bool started_sandbox = StartBPFSandbox(command_line, process_type);
269 CHECK(started_sandbox);
270 return true;
272 #endif
273 return false;
276 bool SandboxSeccompBPF::StartSandboxWithExternalPolicy(
277 scoped_ptr<sandbox::SandboxBPFPolicy> policy) {
278 #if defined(USE_SECCOMP_BPF)
279 if (IsSeccompBPFDesired() && SupportsSandbox()) {
280 CHECK(policy);
281 StartSandboxWithPolicy(policy.release());
282 return true;
284 #endif // defined(USE_SECCOMP_BPF)
285 return false;
288 scoped_ptr<sandbox::SandboxBPFPolicy>
289 SandboxSeccompBPF::GetBaselinePolicy() {
290 #if defined(USE_SECCOMP_BPF)
291 return scoped_ptr<sandbox::SandboxBPFPolicy>(new BaselinePolicy);
292 #else
293 return scoped_ptr<sandbox::SandboxBPFPolicy>();
294 #endif // defined(USE_SECCOMP_BPF)
297 } // namespace content