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"
9 #include <sys/socket.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 using sandbox::BaselinePolicy
;
38 using sandbox::SandboxBPF
;
39 using sandbox::SyscallSets
;
40 using sandbox::bpf_dsl::Allow
;
41 using sandbox::bpf_dsl::ResultExpr
;
45 // Make sure that seccomp-bpf does not get disabled by mistake. Also make sure
46 // that we think twice about this when adding a new architecture.
47 #if !defined(ARCH_CPU_ARM64)
48 #error "Seccomp-bpf disabled on supported architecture!"
49 #endif // !defined(ARCH_CPU_ARM64)
55 #if defined(USE_SECCOMP_BPF)
58 void StartSandboxWithPolicy(sandbox::SandboxBPFPolicy
* policy
);
60 inline bool IsChromeOS() {
61 #if defined(OS_CHROMEOS)
68 inline bool IsArchitectureArm() {
76 class BlacklistDebugAndNumaPolicy
: public SandboxBPFBasePolicy
{
78 BlacklistDebugAndNumaPolicy() {}
79 virtual ~BlacklistDebugAndNumaPolicy() {}
81 virtual ResultExpr
EvaluateSyscall(int system_call_number
) const OVERRIDE
;
84 DISALLOW_COPY_AND_ASSIGN(BlacklistDebugAndNumaPolicy
);
87 ResultExpr
BlacklistDebugAndNumaPolicy::EvaluateSyscall(int sysno
) const {
88 if (SyscallSets::IsDebug(sysno
) || SyscallSets::IsNuma(sysno
))
89 return sandbox::CrashSIGSYS();
94 class AllowAllPolicy
: public SandboxBPFBasePolicy
{
97 virtual ~AllowAllPolicy() {}
99 virtual ResultExpr
EvaluateSyscall(int system_call_number
) const OVERRIDE
;
102 DISALLOW_COPY_AND_ASSIGN(AllowAllPolicy
);
105 // Allow all syscalls.
106 // This will still deny x32 or IA32 calls in 64 bits mode or
107 // 64 bits system calls in compatibility mode.
108 ResultExpr
AllowAllPolicy::EvaluateSyscall(int sysno
) const {
112 // If a BPF policy is engaged for |process_type|, run a few sanity checks.
113 void RunSandboxSanityChecks(const std::string
& process_type
) {
114 if (process_type
== switches::kRendererProcess
||
115 process_type
== switches::kGpuProcess
||
116 process_type
== switches::kPpapiPluginProcess
) {
120 // Without the sandbox, this would EBADF.
121 syscall_ret
= fchmod(-1, 07777);
122 CHECK_EQ(-1, syscall_ret
);
123 CHECK_EQ(EPERM
, errno
);
125 // Run most of the sanity checks only in DEBUG mode to avoid a perf.
128 // open() must be restricted.
129 syscall_ret
= open("/etc/passwd", O_RDONLY
);
130 CHECK_EQ(-1, syscall_ret
);
131 CHECK_EQ(SandboxBPFBasePolicy::GetFSDeniedErrno(), errno
);
133 // We should never allow the creation of netlink sockets.
134 syscall_ret
= socket(AF_NETLINK
, SOCK_DGRAM
, 0);
135 CHECK_EQ(-1, syscall_ret
);
136 CHECK_EQ(EPERM
, errno
);
137 #endif // !defined(NDEBUG)
142 // This function takes ownership of |policy|.
143 void StartSandboxWithPolicy(sandbox::SandboxBPFPolicy
* policy
) {
144 // Starting the sandbox is a one-way operation. The kernel doesn't allow
145 // us to unload a sandbox policy after it has been started. Nonetheless,
146 // in order to make the use of the "Sandbox" object easier, we allow for
147 // the object to be destroyed after the sandbox has been started. Note that
148 // doing so does not stop the sandbox.
150 sandbox
.SetSandboxPolicy(policy
);
151 CHECK(sandbox
.StartSandbox(SandboxBPF::PROCESS_SINGLE_THREADED
));
154 // nacl_helper needs to be tiny and includes only part of content/
155 // in its dependencies. Make sure to not link things that are not needed.
156 #if !defined(IN_NACL_HELPER)
157 scoped_ptr
<SandboxBPFBasePolicy
> GetGpuProcessSandbox() {
158 const base::CommandLine
& command_line
=
159 *base::CommandLine::ForCurrentProcess();
160 bool allow_sysv_shm
= false;
161 if (command_line
.HasSwitch(switches::kGpuSandboxAllowSysVShm
)) {
162 DCHECK(IsArchitectureArm());
163 allow_sysv_shm
= true;
166 if (IsChromeOS() && IsArchitectureArm()) {
167 return scoped_ptr
<SandboxBPFBasePolicy
>(
168 new CrosArmGpuProcessPolicy(allow_sysv_shm
));
170 return scoped_ptr
<SandboxBPFBasePolicy
>(new GpuProcessPolicy
);
174 // Initialize the seccomp-bpf sandbox.
175 bool StartBPFSandbox(const base::CommandLine
& command_line
,
176 const std::string
& process_type
) {
177 scoped_ptr
<SandboxBPFBasePolicy
> policy
;
179 if (process_type
== switches::kGpuProcess
) {
180 policy
.reset(GetGpuProcessSandbox().release());
181 } else if (process_type
== switches::kRendererProcess
) {
182 policy
.reset(new RendererProcessPolicy
);
183 } else if (process_type
== switches::kPpapiPluginProcess
) {
184 policy
.reset(new PpapiProcessPolicy
);
185 } else if (process_type
== switches::kUtilityProcess
) {
186 policy
.reset(new UtilityProcessPolicy
);
189 policy
.reset(new AllowAllPolicy
);
192 CHECK(policy
->PreSandboxHook());
193 StartSandboxWithPolicy(policy
.release());
195 RunSandboxSanityChecks(process_type
);
198 #else // defined(IN_NACL_HELPER)
199 bool StartBPFSandbox(const base::CommandLine
& command_line
,
200 const std::string
& process_type
) {
202 // Avoid -Wunused-function with no-op code.
203 ignore_result(IsChromeOS
);
204 ignore_result(IsArchitectureArm
);
205 ignore_result(RunSandboxSanityChecks
);
208 #endif // !defined(IN_NACL_HELPER)
212 #endif // USE_SECCOMP_BPF
214 // Is seccomp BPF globally enabled?
215 bool SandboxSeccompBPF::IsSeccompBPFDesired() {
216 const base::CommandLine
& command_line
=
217 *base::CommandLine::ForCurrentProcess();
218 if (!command_line
.HasSwitch(switches::kNoSandbox
) &&
219 !command_line
.HasSwitch(switches::kDisableSeccompFilterSandbox
)) {
226 bool SandboxSeccompBPF::ShouldEnableSeccompBPF(
227 const std::string
& process_type
) {
228 #if defined(USE_SECCOMP_BPF)
229 const base::CommandLine
& command_line
=
230 *base::CommandLine::ForCurrentProcess();
231 if (process_type
== switches::kGpuProcess
)
232 return !command_line
.HasSwitch(switches::kDisableGpuSandbox
);
235 #endif // USE_SECCOMP_BPF
239 bool SandboxSeccompBPF::SupportsSandbox() {
240 #if defined(USE_SECCOMP_BPF)
241 // TODO(jln): pass the saved proc_fd_ from the LinuxSandbox singleton
243 SandboxBPF::SandboxStatus bpf_sandbox_status
=
244 SandboxBPF::SupportsSeccompSandbox(-1);
245 // Kernel support is what we are interested in here. Other status
246 // such as STATUS_UNAVAILABLE (has threads) still indicate kernel support.
247 // We make this a negative check, since if there is a bug, we would rather
248 // "fail closed" (expect a sandbox to be available and try to start it).
249 if (bpf_sandbox_status
!= SandboxBPF::STATUS_UNSUPPORTED
) {
256 bool SandboxSeccompBPF::StartSandbox(const std::string
& process_type
) {
257 #if defined(USE_SECCOMP_BPF)
258 const base::CommandLine
& command_line
=
259 *base::CommandLine::ForCurrentProcess();
261 if (IsSeccompBPFDesired() && // Global switches policy.
262 ShouldEnableSeccompBPF(process_type
) && // Process-specific policy.
264 // If the kernel supports the sandbox, and if the command line says we
265 // should enable it, enable it or die.
266 bool started_sandbox
= StartBPFSandbox(command_line
, process_type
);
267 CHECK(started_sandbox
);
274 bool SandboxSeccompBPF::StartSandboxWithExternalPolicy(
275 scoped_ptr
<sandbox::bpf_dsl::SandboxBPFDSLPolicy
> policy
) {
276 #if defined(USE_SECCOMP_BPF)
277 if (IsSeccompBPFDesired() && SupportsSandbox()) {
279 StartSandboxWithPolicy(policy
.release());
282 #endif // defined(USE_SECCOMP_BPF)
286 scoped_ptr
<sandbox::bpf_dsl::SandboxBPFDSLPolicy
>
287 SandboxSeccompBPF::GetBaselinePolicy() {
288 #if defined(USE_SECCOMP_BPF)
289 return scoped_ptr
<sandbox::bpf_dsl::SandboxBPFDSLPolicy
>(new BaselinePolicy
);
291 return scoped_ptr
<sandbox::bpf_dsl::SandboxBPFDSLPolicy
>();
292 #endif // defined(USE_SECCOMP_BPF)
295 } // namespace content