Updating XTBs based on .GRDs from branch master
[chromium-blink-merge.git] / sandbox / linux / seccomp-bpf / sandbox_bpf.cc
blob77faba4a47bd683f2d08705c7d2904f2575e9d58
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 #include <errno.h>
8 #include <sys/prctl.h>
9 #include <sys/types.h>
10 #include <unistd.h>
12 #include "base/compiler_specific.h"
13 #include "base/files/scoped_file.h"
14 #include "base/logging.h"
15 #include "base/macros.h"
16 #include "base/memory/scoped_ptr.h"
17 #include "base/posix/eintr_wrapper.h"
18 #include "base/third_party/valgrind/valgrind.h"
19 #include "sandbox/linux/bpf_dsl/codegen.h"
20 #include "sandbox/linux/bpf_dsl/policy.h"
21 #include "sandbox/linux/bpf_dsl/policy_compiler.h"
22 #include "sandbox/linux/bpf_dsl/seccomp_macros.h"
23 #include "sandbox/linux/bpf_dsl/syscall_set.h"
24 #include "sandbox/linux/seccomp-bpf/die.h"
25 #include "sandbox/linux/seccomp-bpf/syscall.h"
26 #include "sandbox/linux/seccomp-bpf/trap.h"
27 #include "sandbox/linux/services/proc_util.h"
28 #include "sandbox/linux/services/syscall_wrappers.h"
29 #include "sandbox/linux/services/thread_helpers.h"
30 #include "sandbox/linux/system_headers/linux_filter.h"
31 #include "sandbox/linux/system_headers/linux_seccomp.h"
32 #include "sandbox/linux/system_headers/linux_syscalls.h"
34 namespace sandbox {
36 namespace {
38 bool IsRunningOnValgrind() { return RUNNING_ON_VALGRIND; }
40 bool IsSingleThreaded(int proc_fd) {
41 return ThreadHelpers::IsSingleThreaded(proc_fd);
44 // Check if the kernel supports seccomp-filter (a.k.a. seccomp mode 2) via
45 // prctl().
46 bool KernelSupportsSeccompBPF() {
47 errno = 0;
48 const int rv = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, nullptr);
50 if (rv == -1 && EFAULT == errno) {
51 return true;
53 return false;
56 // LG introduced a buggy syscall, sys_set_media_ext, with the same number as
57 // seccomp. Return true if the current kernel has this buggy syscall.
59 // We want this to work with upcoming versions of seccomp, so we pass bogus
60 // flags that are unlikely to ever be used by the kernel. A normal kernel would
61 // return -EINVAL, but a buggy LG kernel would return 1.
62 bool KernelHasLGBug() {
63 #if defined(OS_ANDROID)
64 // sys_set_media will see this as NULL, which should be a safe (non-crashing)
65 // way to invoke it. A genuine seccomp syscall will see it as
66 // SECCOMP_SET_MODE_STRICT.
67 const unsigned int operation = 0;
68 // Chosen by fair dice roll. Guaranteed to be random.
69 const unsigned int flags = 0xf7a46a5c;
70 const int rv = sys_seccomp(operation, flags, nullptr);
71 // A genuine kernel would return -EINVAL (which would set rv to -1 and errno
72 // to EINVAL), or at the very least return some kind of error (which would
73 // set rv to -1). Any other behavior indicates that whatever code received
74 // our syscall was not the real seccomp.
75 if (rv != -1) {
76 return true;
78 #endif // defined(OS_ANDROID)
80 return false;
83 // Check if the kernel supports seccomp-filter via the seccomp system call
84 // and the TSYNC feature to enable seccomp on all threads.
85 bool KernelSupportsSeccompTsync() {
86 if (KernelHasLGBug()) {
87 return false;
90 errno = 0;
91 const int rv =
92 sys_seccomp(SECCOMP_SET_MODE_FILTER, SECCOMP_FILTER_FLAG_TSYNC, nullptr);
94 if (rv == -1 && errno == EFAULT) {
95 return true;
96 } else {
97 // TODO(jln): turn these into DCHECK after 417888 is considered fixed.
98 CHECK_EQ(-1, rv);
99 CHECK(ENOSYS == errno || EINVAL == errno);
100 return false;
104 uint64_t EscapePC() {
105 intptr_t rv = Syscall::Call(-1);
106 if (rv == -1 && errno == ENOSYS) {
107 return 0;
109 return static_cast<uint64_t>(static_cast<uintptr_t>(rv));
112 } // namespace
114 SandboxBPF::SandboxBPF(bpf_dsl::Policy* policy)
115 : proc_fd_(), sandbox_has_started_(false), policy_(policy) {
118 SandboxBPF::~SandboxBPF() {
121 // static
122 bool SandboxBPF::SupportsSeccompSandbox(SeccompLevel level) {
123 // Never pretend to support seccomp with Valgrind, as it
124 // throws the tool off.
125 if (IsRunningOnValgrind()) {
126 return false;
129 switch (level) {
130 case SeccompLevel::SINGLE_THREADED:
131 return KernelSupportsSeccompBPF();
132 case SeccompLevel::MULTI_THREADED:
133 return KernelSupportsSeccompTsync();
135 NOTREACHED();
136 return false;
139 bool SandboxBPF::StartSandbox(SeccompLevel seccomp_level) {
140 DCHECK(policy_);
141 CHECK(seccomp_level == SeccompLevel::SINGLE_THREADED ||
142 seccomp_level == SeccompLevel::MULTI_THREADED);
144 if (sandbox_has_started_) {
145 SANDBOX_DIE(
146 "Cannot repeatedly start sandbox. Create a separate Sandbox "
147 "object instead.");
148 return false;
151 if (!proc_fd_.is_valid()) {
152 SetProcFd(ProcUtil::OpenProc());
155 const bool supports_tsync = KernelSupportsSeccompTsync();
157 if (seccomp_level == SeccompLevel::SINGLE_THREADED) {
158 // Wait for /proc/self/task/ to update if needed and assert the
159 // process is single threaded.
160 ThreadHelpers::AssertSingleThreaded(proc_fd_.get());
161 } else if (seccomp_level == SeccompLevel::MULTI_THREADED) {
162 if (IsSingleThreaded(proc_fd_.get())) {
163 SANDBOX_DIE("Cannot start sandbox; "
164 "process may be single-threaded when reported as not");
165 return false;
167 if (!supports_tsync) {
168 SANDBOX_DIE("Cannot start sandbox; kernel does not support synchronizing "
169 "filters for a threadgroup");
170 return false;
174 // We no longer need access to any files in /proc. We want to do this
175 // before installing the filters, just in case that our policy denies
176 // close().
177 if (proc_fd_.is_valid()) {
178 proc_fd_.reset();
181 // Install the filters.
182 InstallFilter(supports_tsync ||
183 seccomp_level == SeccompLevel::MULTI_THREADED);
185 return true;
188 void SandboxBPF::SetProcFd(base::ScopedFD proc_fd) {
189 proc_fd_.swap(proc_fd);
192 // static
193 bool SandboxBPF::IsValidSyscallNumber(int sysnum) {
194 return SyscallSet::IsValid(sysnum);
197 // static
198 bool SandboxBPF::IsRequiredForUnsafeTrap(int sysno) {
199 return bpf_dsl::PolicyCompiler::IsRequiredForUnsafeTrap(sysno);
202 // static
203 intptr_t SandboxBPF::ForwardSyscall(const struct arch_seccomp_data& args) {
204 return Syscall::Call(
205 args.nr, static_cast<intptr_t>(args.args[0]),
206 static_cast<intptr_t>(args.args[1]), static_cast<intptr_t>(args.args[2]),
207 static_cast<intptr_t>(args.args[3]), static_cast<intptr_t>(args.args[4]),
208 static_cast<intptr_t>(args.args[5]));
211 scoped_ptr<CodeGen::Program> SandboxBPF::AssembleFilter(
212 bool force_verification) {
213 #if !defined(NDEBUG)
214 force_verification = true;
215 #endif
216 DCHECK(policy_);
218 bpf_dsl::PolicyCompiler compiler(policy_.get(), Trap::Registry());
219 if (Trap::SandboxDebuggingAllowedByUser()) {
220 compiler.DangerousSetEscapePC(EscapePC());
222 return compiler.Compile(force_verification);
225 void SandboxBPF::InstallFilter(bool must_sync_threads) {
226 // We want to be very careful in not imposing any requirements on the
227 // policies that are set with SetSandboxPolicy(). This means, as soon as
228 // the sandbox is active, we shouldn't be relying on libraries that could
229 // be making system calls. This, for example, means we should avoid
230 // using the heap and we should avoid using STL functions.
231 // Temporarily copy the contents of the "program" vector into a
232 // stack-allocated array; and then explicitly destroy that object.
233 // This makes sure we don't ex- or implicitly call new/delete after we
234 // installed the BPF filter program in the kernel. Depending on the
235 // system memory allocator that is in effect, these operators can result
236 // in system calls to things like munmap() or brk().
237 CodeGen::Program* program = AssembleFilter(false).release();
239 struct sock_filter bpf[program->size()];
240 const struct sock_fprog prog = {static_cast<unsigned short>(program->size()),
241 bpf};
242 memcpy(bpf, &(*program)[0], sizeof(bpf));
243 delete program;
245 // Make an attempt to release memory that is no longer needed here, rather
246 // than in the destructor. Try to avoid as much as possible to presume of
247 // what will be possible to do in the new (sandboxed) execution environment.
248 policy_.reset();
250 if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) {
251 SANDBOX_DIE("Kernel refuses to enable no-new-privs");
254 // Install BPF filter program. If the thread state indicates multi-threading
255 // support, then the kernel hass the seccomp system call. Otherwise, fall
256 // back on prctl, which requires the process to be single-threaded.
257 if (must_sync_threads) {
258 int rv =
259 sys_seccomp(SECCOMP_SET_MODE_FILTER, SECCOMP_FILTER_FLAG_TSYNC, &prog);
260 if (rv) {
261 SANDBOX_DIE(
262 "Kernel refuses to turn on and synchronize threads for BPF filters");
264 } else {
265 if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog)) {
266 SANDBOX_DIE("Kernel refuses to turn on BPF filters");
270 sandbox_has_started_ = true;
273 } // namespace sandbox