Add ICU message format support
[chromium-blink-merge.git] / content / common / sandbox_linux / sandbox_seccomp_bpf_linux.cc
blob79adbee4bba299084db48ad733e3fe9c22d53d45
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 "sandbox/linux/seccomp-bpf-helpers/baseline_policy.h"
32 #include "sandbox/linux/seccomp-bpf-helpers/sigsys_handlers.h"
33 #include "sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.h"
34 #include "sandbox/linux/seccomp-bpf-helpers/syscall_sets.h"
35 #include "sandbox/linux/seccomp-bpf/sandbox_bpf.h"
36 #include "sandbox/linux/system_headers/linux_syscalls.h"
38 #if !defined(IN_NACL_HELPER)
39 #include "ui/gl/gl_switches.h"
40 #endif // !defined(IN_NACL_HELPER)
42 using sandbox::BaselinePolicy;
43 using sandbox::SandboxBPF;
44 using sandbox::SyscallSets;
45 using sandbox::bpf_dsl::Allow;
46 using sandbox::bpf_dsl::ResultExpr;
48 #else
50 // Make sure that seccomp-bpf does not get disabled by mistake. Also make sure
51 // that we think twice about this when adding a new architecture.
52 #if !defined(ARCH_CPU_ARM64)
53 #error "Seccomp-bpf disabled on supported architecture!"
54 #endif // !defined(ARCH_CPU_ARM64)
56 #endif //
58 namespace content {
60 #if defined(USE_SECCOMP_BPF)
61 namespace {
63 // This function takes ownership of |policy|.
64 void StartSandboxWithPolicy(sandbox::bpf_dsl::Policy* policy,
65 base::ScopedFD proc_fd) {
66 // Starting the sandbox is a one-way operation. The kernel doesn't allow
67 // us to unload a sandbox policy after it has been started. Nonetheless,
68 // in order to make the use of the "Sandbox" object easier, we allow for
69 // the object to be destroyed after the sandbox has been started. Note that
70 // doing so does not stop the sandbox.
71 SandboxBPF sandbox(policy);
73 sandbox.SetProcFd(proc_fd.Pass());
74 CHECK(sandbox.StartSandbox(SandboxBPF::SeccompLevel::SINGLE_THREADED));
77 #if !defined(OS_NACL_NONSFI)
79 inline bool IsChromeOS() {
80 #if defined(OS_CHROMEOS)
81 return true;
82 #else
83 return false;
84 #endif
87 inline bool IsArchitectureArm() {
88 #if defined(__arm__)
89 return true;
90 #else
91 return false;
92 #endif
95 class BlacklistDebugAndNumaPolicy : public SandboxBPFBasePolicy {
96 public:
97 BlacklistDebugAndNumaPolicy() {}
98 ~BlacklistDebugAndNumaPolicy() override {}
100 ResultExpr EvaluateSyscall(int system_call_number) const override;
102 private:
103 DISALLOW_COPY_AND_ASSIGN(BlacklistDebugAndNumaPolicy);
106 ResultExpr BlacklistDebugAndNumaPolicy::EvaluateSyscall(int sysno) const {
107 if (SyscallSets::IsDebug(sysno) || SyscallSets::IsNuma(sysno))
108 return sandbox::CrashSIGSYS();
110 return Allow();
113 class AllowAllPolicy : public SandboxBPFBasePolicy {
114 public:
115 AllowAllPolicy() {}
116 ~AllowAllPolicy() override {}
118 ResultExpr EvaluateSyscall(int system_call_number) const override;
120 private:
121 DISALLOW_COPY_AND_ASSIGN(AllowAllPolicy);
124 // Allow all syscalls.
125 // This will still deny x32 or IA32 calls in 64 bits mode or
126 // 64 bits system calls in compatibility mode.
127 ResultExpr AllowAllPolicy::EvaluateSyscall(int sysno) const {
128 return Allow();
131 // If a BPF policy is engaged for |process_type|, run a few sanity checks.
132 void RunSandboxSanityChecks(const std::string& process_type) {
133 if (process_type == switches::kRendererProcess ||
134 process_type == switches::kGpuProcess ||
135 process_type == switches::kPpapiPluginProcess) {
136 int syscall_ret;
137 errno = 0;
139 // Without the sandbox, this would EBADF.
140 syscall_ret = fchmod(-1, 07777);
141 CHECK_EQ(-1, syscall_ret);
142 CHECK_EQ(EPERM, errno);
144 // Run most of the sanity checks only in DEBUG mode to avoid a perf.
145 // impact.
146 #if !defined(NDEBUG)
147 // open() must be restricted.
148 syscall_ret = open("/etc/passwd", O_RDONLY);
149 CHECK_EQ(-1, syscall_ret);
150 CHECK_EQ(SandboxBPFBasePolicy::GetFSDeniedErrno(), errno);
152 // We should never allow the creation of netlink sockets.
153 syscall_ret = socket(AF_NETLINK, SOCK_DGRAM, 0);
154 CHECK_EQ(-1, syscall_ret);
155 CHECK_EQ(EPERM, errno);
156 #endif // !defined(NDEBUG)
160 // nacl_helper needs to be tiny and includes only part of content/
161 // in its dependencies. Make sure to not link things that are not needed.
162 #if !defined(IN_NACL_HELPER)
163 scoped_ptr<SandboxBPFBasePolicy> GetGpuProcessSandbox() {
164 const base::CommandLine& command_line =
165 *base::CommandLine::ForCurrentProcess();
166 bool allow_sysv_shm = false;
167 if (command_line.HasSwitch(switches::kGpuSandboxAllowSysVShm)) {
168 DCHECK(IsArchitectureArm());
169 allow_sysv_shm = true;
172 if (IsChromeOS() && IsArchitectureArm()) {
173 return scoped_ptr<SandboxBPFBasePolicy>(
174 new CrosArmGpuProcessPolicy(allow_sysv_shm));
175 } else {
176 bool allow_mincore = command_line.HasSwitch(switches::kUseGL) &&
177 command_line.GetSwitchValueASCII(switches::kUseGL) ==
178 gfx::kGLImplementationEGLName;
179 return scoped_ptr<SandboxBPFBasePolicy>(
180 new GpuProcessPolicy(allow_mincore));
184 // Initialize the seccomp-bpf sandbox.
185 bool StartBPFSandbox(const base::CommandLine& command_line,
186 const std::string& process_type,
187 base::ScopedFD proc_fd) {
188 scoped_ptr<SandboxBPFBasePolicy> policy;
190 if (process_type == switches::kGpuProcess) {
191 policy.reset(GetGpuProcessSandbox().release());
192 } else if (process_type == switches::kRendererProcess) {
193 policy.reset(new RendererProcessPolicy);
194 } else if (process_type == switches::kPpapiPluginProcess) {
195 policy.reset(new PpapiProcessPolicy);
196 } else if (process_type == switches::kUtilityProcess) {
197 policy.reset(new UtilityProcessPolicy);
198 } else {
199 NOTREACHED();
200 policy.reset(new AllowAllPolicy);
203 CHECK(policy->PreSandboxHook());
204 StartSandboxWithPolicy(policy.release(), proc_fd.Pass());
206 RunSandboxSanityChecks(process_type);
207 return true;
209 #else // defined(IN_NACL_HELPER)
210 bool StartBPFSandbox(const base::CommandLine& command_line,
211 const std::string& process_type) {
212 NOTREACHED();
213 // Avoid -Wunused-function with no-op code.
214 ignore_result(IsChromeOS);
215 ignore_result(IsArchitectureArm);
216 ignore_result(RunSandboxSanityChecks);
217 return false;
219 #endif // !defined(IN_NACL_HELPER)
220 #endif // !defined(OS_NACL_NONSFI)
222 } // namespace
224 #endif // USE_SECCOMP_BPF
226 // Is seccomp BPF globally enabled?
227 bool SandboxSeccompBPF::IsSeccompBPFDesired() {
228 const base::CommandLine& command_line =
229 *base::CommandLine::ForCurrentProcess();
230 if (!command_line.HasSwitch(switches::kNoSandbox) &&
231 !command_line.HasSwitch(switches::kDisableSeccompFilterSandbox)) {
232 return true;
233 } else {
234 return false;
238 #if !defined(OS_NACL_NONSFI)
239 bool SandboxSeccompBPF::ShouldEnableSeccompBPF(
240 const std::string& process_type) {
241 #if defined(USE_SECCOMP_BPF)
242 const base::CommandLine& command_line =
243 *base::CommandLine::ForCurrentProcess();
244 if (process_type == switches::kGpuProcess)
245 return !command_line.HasSwitch(switches::kDisableGpuSandbox);
247 return true;
248 #endif // USE_SECCOMP_BPF
249 return false;
251 #endif // !defined(OS_NACL_NONSFI)
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 #if !defined(OS_NACL_NONSFI)
262 bool SandboxSeccompBPF::SupportsSandboxWithTsync() {
263 #if defined(USE_SECCOMP_BPF)
264 return SandboxBPF::SupportsSeccompSandbox(
265 SandboxBPF::SeccompLevel::MULTI_THREADED);
266 #endif
267 return false;
270 bool SandboxSeccompBPF::StartSandbox(const std::string& process_type,
271 base::ScopedFD proc_fd) {
272 #if defined(USE_SECCOMP_BPF)
273 const base::CommandLine& command_line =
274 *base::CommandLine::ForCurrentProcess();
276 if (IsSeccompBPFDesired() && // Global switches policy.
277 ShouldEnableSeccompBPF(process_type) && // Process-specific policy.
278 SupportsSandbox()) {
279 // If the kernel supports the sandbox, and if the command line says we
280 // should enable it, enable it or die.
281 bool started_sandbox =
282 StartBPFSandbox(command_line, process_type, proc_fd.Pass());
283 CHECK(started_sandbox);
284 return true;
286 #endif
287 return false;
289 #endif // !defined(OS_NACL_NONSFI)
291 bool SandboxSeccompBPF::StartSandboxWithExternalPolicy(
292 scoped_ptr<sandbox::bpf_dsl::Policy> policy,
293 base::ScopedFD proc_fd) {
294 #if defined(USE_SECCOMP_BPF)
295 if (IsSeccompBPFDesired() && SupportsSandbox()) {
296 CHECK(policy);
297 StartSandboxWithPolicy(policy.release(), proc_fd.Pass());
298 return true;
300 #endif // defined(USE_SECCOMP_BPF)
301 return false;
304 #if !defined(OS_NACL_NONSFI)
305 scoped_ptr<sandbox::bpf_dsl::Policy> SandboxSeccompBPF::GetBaselinePolicy() {
306 #if defined(USE_SECCOMP_BPF)
307 return scoped_ptr<sandbox::bpf_dsl::Policy>(new BaselinePolicy);
308 #else
309 return scoped_ptr<sandbox::bpf_dsl::Policy>();
310 #endif // defined(USE_SECCOMP_BPF)
312 #endif // !defined(OS_NACL_NONSFI)
314 } // namespace content