Roll src/third_party/WebKit e0eac24:489c548 (svn 193311:193320)
[chromium-blink-merge.git] / sandbox / linux / seccomp-bpf / sandbox_bpf.cc
blobc96642ec408685548d96f056731469bc4844a0dc
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 "sandbox/linux/seccomp-bpf/sandbox_bpf.h"
7 // Some headers on Android are missing cdefs: crbug.com/172337.
8 // (We can't use OS_ANDROID here since build_config.h is not included).
9 #if defined(ANDROID)
10 #include <sys/cdefs.h>
11 #endif
13 #include <errno.h>
14 #include <linux/filter.h>
15 #include <sys/prctl.h>
16 #include <sys/types.h>
17 #include <unistd.h>
19 #include "base/compiler_specific.h"
20 #include "base/files/scoped_file.h"
21 #include "base/logging.h"
22 #include "base/macros.h"
23 #include "base/memory/scoped_ptr.h"
24 #include "base/posix/eintr_wrapper.h"
25 #include "base/third_party/valgrind/valgrind.h"
26 #include "sandbox/linux/bpf_dsl/codegen.h"
27 #include "sandbox/linux/bpf_dsl/policy.h"
28 #include "sandbox/linux/bpf_dsl/policy_compiler.h"
29 #include "sandbox/linux/bpf_dsl/seccomp_macros.h"
30 #include "sandbox/linux/bpf_dsl/syscall_set.h"
31 #include "sandbox/linux/seccomp-bpf/die.h"
32 #include "sandbox/linux/seccomp-bpf/syscall.h"
33 #include "sandbox/linux/seccomp-bpf/trap.h"
34 #include "sandbox/linux/services/proc_util.h"
35 #include "sandbox/linux/services/syscall_wrappers.h"
36 #include "sandbox/linux/services/thread_helpers.h"
37 #include "sandbox/linux/system_headers/linux_seccomp.h"
38 #include "sandbox/linux/system_headers/linux_syscalls.h"
40 namespace sandbox {
42 namespace {
44 bool IsRunningOnValgrind() { return RUNNING_ON_VALGRIND; }
46 bool IsSingleThreaded(int proc_fd) {
47 return ThreadHelpers::IsSingleThreaded(proc_fd);
50 // Check if the kernel supports seccomp-filter (a.k.a. seccomp mode 2) via
51 // prctl().
52 bool KernelSupportsSeccompBPF() {
53 errno = 0;
54 const int rv = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, nullptr);
56 if (rv == -1 && EFAULT == errno) {
57 return true;
59 return false;
62 // Check if the kernel supports seccomp-filter via the seccomp system call
63 // and the TSYNC feature to enable seccomp on all threads.
64 bool KernelSupportsSeccompTsync() {
65 errno = 0;
66 const int rv =
67 sys_seccomp(SECCOMP_SET_MODE_FILTER, SECCOMP_FILTER_FLAG_TSYNC, nullptr);
69 if (rv == -1 && errno == EFAULT) {
70 return true;
71 } else {
72 // TODO(jln): turn these into DCHECK after 417888 is considered fixed.
73 CHECK_EQ(-1, rv);
74 CHECK(ENOSYS == errno || EINVAL == errno);
75 return false;
79 uint64_t EscapePC() {
80 intptr_t rv = Syscall::Call(-1);
81 if (rv == -1 && errno == ENOSYS) {
82 return 0;
84 return static_cast<uint64_t>(static_cast<uintptr_t>(rv));
87 } // namespace
89 SandboxBPF::SandboxBPF(bpf_dsl::Policy* policy)
90 : proc_fd_(), sandbox_has_started_(false), policy_(policy) {
93 SandboxBPF::~SandboxBPF() {
96 // static
97 bool SandboxBPF::SupportsSeccompSandbox(SeccompLevel level) {
98 // Never pretend to support seccomp with Valgrind, as it
99 // throws the tool off.
100 if (IsRunningOnValgrind()) {
101 return false;
104 switch (level) {
105 case SeccompLevel::SINGLE_THREADED:
106 return KernelSupportsSeccompBPF();
107 case SeccompLevel::MULTI_THREADED:
108 return KernelSupportsSeccompTsync();
110 NOTREACHED();
111 return false;
114 bool SandboxBPF::StartSandbox(SeccompLevel seccomp_level) {
115 DCHECK(policy_);
116 CHECK(seccomp_level == SeccompLevel::SINGLE_THREADED ||
117 seccomp_level == SeccompLevel::MULTI_THREADED);
119 if (sandbox_has_started_) {
120 SANDBOX_DIE(
121 "Cannot repeatedly start sandbox. Create a separate Sandbox "
122 "object instead.");
123 return false;
126 if (!proc_fd_.is_valid()) {
127 SetProcFd(ProcUtil::OpenProc());
130 const bool supports_tsync = KernelSupportsSeccompTsync();
132 if (seccomp_level == SeccompLevel::SINGLE_THREADED) {
133 // Wait for /proc/self/task/ to update if needed and assert the
134 // process is single threaded.
135 ThreadHelpers::AssertSingleThreaded(proc_fd_.get());
136 } else if (seccomp_level == SeccompLevel::MULTI_THREADED) {
137 if (IsSingleThreaded(proc_fd_.get())) {
138 SANDBOX_DIE("Cannot start sandbox; "
139 "process may be single-threaded when reported as not");
140 return false;
142 if (!supports_tsync) {
143 SANDBOX_DIE("Cannot start sandbox; kernel does not support synchronizing "
144 "filters for a threadgroup");
145 return false;
149 // We no longer need access to any files in /proc. We want to do this
150 // before installing the filters, just in case that our policy denies
151 // close().
152 if (proc_fd_.is_valid()) {
153 proc_fd_.reset();
156 // Install the filters.
157 InstallFilter(supports_tsync ||
158 seccomp_level == SeccompLevel::MULTI_THREADED);
160 return true;
163 void SandboxBPF::SetProcFd(base::ScopedFD proc_fd) {
164 proc_fd_.swap(proc_fd);
167 // static
168 bool SandboxBPF::IsValidSyscallNumber(int sysnum) {
169 return SyscallSet::IsValid(sysnum);
172 // static
173 bool SandboxBPF::IsRequiredForUnsafeTrap(int sysno) {
174 return bpf_dsl::PolicyCompiler::IsRequiredForUnsafeTrap(sysno);
177 // static
178 intptr_t SandboxBPF::ForwardSyscall(const struct arch_seccomp_data& args) {
179 return Syscall::Call(
180 args.nr, static_cast<intptr_t>(args.args[0]),
181 static_cast<intptr_t>(args.args[1]), static_cast<intptr_t>(args.args[2]),
182 static_cast<intptr_t>(args.args[3]), static_cast<intptr_t>(args.args[4]),
183 static_cast<intptr_t>(args.args[5]));
186 scoped_ptr<CodeGen::Program> SandboxBPF::AssembleFilter(
187 bool force_verification) {
188 #if !defined(NDEBUG)
189 force_verification = true;
190 #endif
191 DCHECK(policy_);
193 bpf_dsl::PolicyCompiler compiler(policy_.get(), Trap::Registry());
194 if (Trap::SandboxDebuggingAllowedByUser()) {
195 compiler.DangerousSetEscapePC(EscapePC());
197 return compiler.Compile(force_verification);
200 void SandboxBPF::InstallFilter(bool must_sync_threads) {
201 // We want to be very careful in not imposing any requirements on the
202 // policies that are set with SetSandboxPolicy(). This means, as soon as
203 // the sandbox is active, we shouldn't be relying on libraries that could
204 // be making system calls. This, for example, means we should avoid
205 // using the heap and we should avoid using STL functions.
206 // Temporarily copy the contents of the "program" vector into a
207 // stack-allocated array; and then explicitly destroy that object.
208 // This makes sure we don't ex- or implicitly call new/delete after we
209 // installed the BPF filter program in the kernel. Depending on the
210 // system memory allocator that is in effect, these operators can result
211 // in system calls to things like munmap() or brk().
212 CodeGen::Program* program = AssembleFilter(false).release();
214 struct sock_filter bpf[program->size()];
215 const struct sock_fprog prog = {static_cast<unsigned short>(program->size()),
216 bpf};
217 memcpy(bpf, &(*program)[0], sizeof(bpf));
218 delete program;
220 // Make an attempt to release memory that is no longer needed here, rather
221 // than in the destructor. Try to avoid as much as possible to presume of
222 // what will be possible to do in the new (sandboxed) execution environment.
223 policy_.reset();
225 if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) {
226 SANDBOX_DIE("Kernel refuses to enable no-new-privs");
229 // Install BPF filter program. If the thread state indicates multi-threading
230 // support, then the kernel hass the seccomp system call. Otherwise, fall
231 // back on prctl, which requires the process to be single-threaded.
232 if (must_sync_threads) {
233 int rv =
234 sys_seccomp(SECCOMP_SET_MODE_FILTER, SECCOMP_FILTER_FLAG_TSYNC, &prog);
235 if (rv) {
236 SANDBOX_DIE(
237 "Kernel refuses to turn on and synchronize threads for BPF filters");
239 } else {
240 if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog)) {
241 SANDBOX_DIE("Kernel refuses to turn on BPF filters");
245 sandbox_has_started_ = true;
248 } // namespace sandbox