Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(393)

Side by Side Diff: sandbox/linux/seccomp-bpf/sandbox_bpf.cc

Issue 761903003: Update from https://crrev.com/306655 (Closed) Base URL: git@github.com:domokit/mojo.git@master
Patch Set: Created 6 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "sandbox/linux/seccomp-bpf/sandbox_bpf.h" 5 #include "sandbox/linux/seccomp-bpf/sandbox_bpf.h"
6 6
7 // Some headers on Android are missing cdefs: crbug.com/172337. 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). 8 // (We can't use OS_ANDROID here since build_config.h is not included).
9 #if defined(ANDROID) 9 #if defined(ANDROID)
10 #include <sys/cdefs.h> 10 #include <sys/cdefs.h>
11 #endif 11 #endif
12 12
13 #include <errno.h> 13 #include <errno.h>
14 #include <fcntl.h>
15 #include <linux/filter.h> 14 #include <linux/filter.h>
16 #include <signal.h>
17 #include <string.h>
18 #include <sys/prctl.h> 15 #include <sys/prctl.h>
19 #include <sys/stat.h>
20 #include <sys/syscall.h>
21 #include <sys/types.h> 16 #include <sys/types.h>
22 #include <sys/wait.h>
23 #include <time.h>
24 #include <unistd.h> 17 #include <unistd.h>
25 18
26 #include "base/compiler_specific.h" 19 #include "base/compiler_specific.h"
20 #include "base/files/scoped_file.h"
27 #include "base/logging.h" 21 #include "base/logging.h"
28 #include "base/macros.h" 22 #include "base/macros.h"
29 #include "base/memory/scoped_ptr.h" 23 #include "base/memory/scoped_ptr.h"
30 #include "base/posix/eintr_wrapper.h" 24 #include "base/posix/eintr_wrapper.h"
31 #include "sandbox/linux/bpf_dsl/bpf_dsl.h" 25 #include "base/third_party/valgrind/valgrind.h"
32 #include "sandbox/linux/bpf_dsl/dump_bpf.h" 26 #include "sandbox/linux/bpf_dsl/dump_bpf.h"
33 #include "sandbox/linux/bpf_dsl/policy.h" 27 #include "sandbox/linux/bpf_dsl/policy.h"
34 #include "sandbox/linux/bpf_dsl/policy_compiler.h" 28 #include "sandbox/linux/bpf_dsl/policy_compiler.h"
35 #include "sandbox/linux/seccomp-bpf/codegen.h" 29 #include "sandbox/linux/seccomp-bpf/codegen.h"
36 #include "sandbox/linux/seccomp-bpf/die.h" 30 #include "sandbox/linux/seccomp-bpf/die.h"
37 #include "sandbox/linux/seccomp-bpf/errorcode.h" 31 #include "sandbox/linux/seccomp-bpf/errorcode.h"
38 #include "sandbox/linux/seccomp-bpf/linux_seccomp.h" 32 #include "sandbox/linux/seccomp-bpf/linux_seccomp.h"
39 #include "sandbox/linux/seccomp-bpf/syscall.h" 33 #include "sandbox/linux/seccomp-bpf/syscall.h"
40 #include "sandbox/linux/seccomp-bpf/syscall_iterator.h" 34 #include "sandbox/linux/seccomp-bpf/syscall_iterator.h"
41 #include "sandbox/linux/seccomp-bpf/trap.h" 35 #include "sandbox/linux/seccomp-bpf/trap.h"
42 #include "sandbox/linux/seccomp-bpf/verifier.h" 36 #include "sandbox/linux/seccomp-bpf/verifier.h"
43 #include "sandbox/linux/services/linux_syscalls.h" 37 #include "sandbox/linux/services/linux_syscalls.h"
44 #include "sandbox/linux/services/syscall_wrappers.h" 38 #include "sandbox/linux/services/syscall_wrappers.h"
45 39 #include "sandbox/linux/services/thread_helpers.h"
46 using sandbox::bpf_dsl::Allow;
47 using sandbox::bpf_dsl::Error;
48 using sandbox::bpf_dsl::ResultExpr;
49 40
50 namespace sandbox { 41 namespace sandbox {
51 42
52 namespace { 43 namespace {
53 44
54 const int kExpectedExitCode = 100; 45 bool IsRunningOnValgrind() { return RUNNING_ON_VALGRIND; }
55 46
56 #if !defined(NDEBUG) 47 bool IsSingleThreaded(int proc_task_fd) {
57 void WriteFailedStderrSetupMessage(int out_fd) { 48 return ThreadHelpers::IsSingleThreaded(proc_task_fd);
58 const char* error_string = strerror(errno);
59 static const char msg[] =
60 "You have reproduced a puzzling issue.\n"
61 "Please, report to crbug.com/152530!\n"
62 "Failed to set up stderr: ";
63 if (HANDLE_EINTR(write(out_fd, msg, sizeof(msg) - 1)) > 0 && error_string &&
64 HANDLE_EINTR(write(out_fd, error_string, strlen(error_string))) > 0 &&
65 HANDLE_EINTR(write(out_fd, "\n", 1))) {
66 }
67 }
68 #endif // !defined(NDEBUG)
69
70 // We define a really simple sandbox policy. It is just good enough for us
71 // to tell that the sandbox has actually been activated.
72 class ProbePolicy : public bpf_dsl::Policy {
73 public:
74 ProbePolicy() {}
75 virtual ~ProbePolicy() {}
76
77 virtual ResultExpr EvaluateSyscall(int sysnum) const override {
78 switch (sysnum) {
79 case __NR_getpid:
80 // Return EPERM so that we can check that the filter actually ran.
81 return Error(EPERM);
82 case __NR_exit_group:
83 // Allow exit() with a non-default return code.
84 return Allow();
85 default:
86 // Make everything else fail in an easily recognizable way.
87 return Error(EINVAL);
88 }
89 }
90
91 private:
92 DISALLOW_COPY_AND_ASSIGN(ProbePolicy);
93 };
94
95 void ProbeProcess(void) {
96 if (sys_getpid() < 0 && errno == EPERM) {
97 sys_exit_group(kExpectedExitCode);
98 }
99 } 49 }
100 50
101 class AllowAllPolicy : public bpf_dsl::Policy { 51 // Check if the kernel supports seccomp-filter (a.k.a. seccomp mode 2) via
102 public: 52 // prctl().
103 AllowAllPolicy() {} 53 bool KernelSupportsSeccompBPF() {
104 virtual ~AllowAllPolicy() {} 54 errno = 0;
55 const int rv = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, nullptr);
105 56
106 virtual ResultExpr EvaluateSyscall(int sysnum) const override { 57 if (rv == -1 && EFAULT == errno) {
107 DCHECK(SandboxBPF::IsValidSyscallNumber(sysnum)); 58 return true;
108 return Allow();
109 } 59 }
110 60 return false;
111 private:
112 DISALLOW_COPY_AND_ASSIGN(AllowAllPolicy);
113 };
114
115 void TryVsyscallProcess(void) {
116 time_t current_time;
117 // time() is implemented as a vsyscall. With an older glibc, with
118 // vsyscall=emulate and some versions of the seccomp BPF patch
119 // we may get SIGKILL-ed. Detect this!
120 if (time(&current_time) != static_cast<time_t>(-1)) {
121 sys_exit_group(kExpectedExitCode);
122 }
123 } 61 }
124 62
125 bool IsSingleThreaded(int proc_fd) { 63 // Check if the kernel supports seccomp-filter via the seccomp system call
126 if (proc_fd < 0) { 64 // and the TSYNC feature to enable seccomp on all threads.
127 // Cannot determine whether program is single-threaded. Hope for 65 bool KernelSupportsSeccompTsync() {
128 // the best... 66 errno = 0;
67 const int rv =
68 sys_seccomp(SECCOMP_SET_MODE_FILTER, SECCOMP_FILTER_FLAG_TSYNC, nullptr);
69
70 if (rv == -1 && errno == EFAULT) {
129 return true; 71 return true;
130 } 72 } else {
131 73 // TODO(jln): turn these into DCHECK after 417888 is considered fixed.
132 struct stat sb; 74 CHECK_EQ(-1, rv);
133 int task = -1; 75 CHECK(ENOSYS == errno || EINVAL == errno);
134 if ((task = openat(proc_fd, "self/task", O_RDONLY | O_DIRECTORY)) < 0 ||
135 fstat(task, &sb) != 0 || sb.st_nlink != 3 || IGNORE_EINTR(close(task))) {
136 if (task >= 0) {
137 if (IGNORE_EINTR(close(task))) {
138 }
139 }
140 return false; 76 return false;
141 } 77 }
142 return true;
143 } 78 }
144 79
145 } // namespace 80 } // namespace
146 81
147 SandboxBPF::SandboxBPF() 82 SandboxBPF::SandboxBPF(bpf_dsl::Policy* policy)
148 : quiet_(false), proc_fd_(-1), sandbox_has_started_(false), policy_() { 83 : proc_task_fd_(), sandbox_has_started_(false), policy_(policy) {
149 } 84 }
150 85
151 SandboxBPF::~SandboxBPF() { 86 SandboxBPF::~SandboxBPF() {
152 } 87 }
153 88
154 bool SandboxBPF::IsValidSyscallNumber(int sysnum) { 89 // static
155 return SyscallSet::IsValid(sysnum); 90 bool SandboxBPF::SupportsSeccompSandbox(SeccompLevel level) {
91 // Never pretend to support seccomp with Valgrind, as it
92 // throws the tool off.
93 if (IsRunningOnValgrind()) {
94 return false;
95 }
96
97 switch (level) {
98 case SeccompLevel::SINGLE_THREADED:
99 return KernelSupportsSeccompBPF();
100 case SeccompLevel::MULTI_THREADED:
101 return KernelSupportsSeccompTsync();
102 }
103 NOTREACHED();
104 return false;
156 } 105 }
157 106
158 bool SandboxBPF::RunFunctionInPolicy(void (*code_in_sandbox)(), 107 bool SandboxBPF::StartSandbox(SeccompLevel seccomp_level) {
159 scoped_ptr<bpf_dsl::Policy> policy) { 108 DCHECK(policy_);
160 // Block all signals before forking a child process. This prevents an 109 CHECK(seccomp_level == SeccompLevel::SINGLE_THREADED ||
161 // attacker from manipulating our test by sending us an unexpected signal. 110 seccomp_level == SeccompLevel::MULTI_THREADED);
162 sigset_t old_mask, new_mask;
163 if (sigfillset(&new_mask) || sigprocmask(SIG_BLOCK, &new_mask, &old_mask)) {
164 SANDBOX_DIE("sigprocmask() failed");
165 }
166 int fds[2];
167 if (pipe2(fds, O_NONBLOCK | O_CLOEXEC)) {
168 SANDBOX_DIE("pipe() failed");
169 }
170 111
171 if (fds[0] <= 2 || fds[1] <= 2) { 112 if (sandbox_has_started_) {
172 SANDBOX_DIE("Process started without standard file descriptors");
173 }
174
175 // This code is using fork() and should only ever run single-threaded.
176 // Most of the code below is "async-signal-safe" and only minor changes
177 // would be needed to support threads.
178 DCHECK(IsSingleThreaded(proc_fd_));
179 pid_t pid = fork();
180 if (pid < 0) {
181 // Die if we cannot fork(). We would probably fail a little later
182 // anyway, as the machine is likely very close to running out of
183 // memory.
184 // But what we don't want to do is return "false", as a crafty
185 // attacker might cause fork() to fail at will and could trick us
186 // into running without a sandbox.
187 sigprocmask(SIG_SETMASK, &old_mask, NULL); // OK, if it fails
188 SANDBOX_DIE("fork() failed unexpectedly");
189 }
190
191 // In the child process
192 if (!pid) {
193 // Test a very simple sandbox policy to verify that we can
194 // successfully turn on sandboxing.
195 Die::EnableSimpleExit();
196
197 errno = 0;
198 if (IGNORE_EINTR(close(fds[0]))) {
199 // This call to close() has been failing in strange ways. See
200 // crbug.com/152530. So we only fail in debug mode now.
201 #if !defined(NDEBUG)
202 WriteFailedStderrSetupMessage(fds[1]);
203 SANDBOX_DIE(NULL);
204 #endif
205 }
206 if (HANDLE_EINTR(dup2(fds[1], 2)) != 2) {
207 // Stderr could very well be a file descriptor to .xsession-errors, or
208 // another file, which could be backed by a file system that could cause
209 // dup2 to fail while trying to close stderr. It's important that we do
210 // not fail on trying to close stderr.
211 // If dup2 fails here, we will continue normally, this means that our
212 // parent won't cause a fatal failure if something writes to stderr in
213 // this child.
214 #if !defined(NDEBUG)
215 // In DEBUG builds, we still want to get a report.
216 WriteFailedStderrSetupMessage(fds[1]);
217 SANDBOX_DIE(NULL);
218 #endif
219 }
220 if (IGNORE_EINTR(close(fds[1]))) {
221 // This call to close() has been failing in strange ways. See
222 // crbug.com/152530. So we only fail in debug mode now.
223 #if !defined(NDEBUG)
224 WriteFailedStderrSetupMessage(fds[1]);
225 SANDBOX_DIE(NULL);
226 #endif
227 }
228
229 SetSandboxPolicy(policy.release());
230 if (!StartSandbox(PROCESS_SINGLE_THREADED)) {
231 SANDBOX_DIE(NULL);
232 }
233
234 // Run our code in the sandbox.
235 code_in_sandbox();
236
237 // code_in_sandbox() is not supposed to return here.
238 SANDBOX_DIE(NULL);
239 }
240
241 // In the parent process.
242 if (IGNORE_EINTR(close(fds[1]))) {
243 SANDBOX_DIE("close() failed");
244 }
245 if (sigprocmask(SIG_SETMASK, &old_mask, NULL)) {
246 SANDBOX_DIE("sigprocmask() failed");
247 }
248 int status;
249 if (HANDLE_EINTR(waitpid(pid, &status, 0)) != pid) {
250 SANDBOX_DIE("waitpid() failed unexpectedly");
251 }
252 bool rc = WIFEXITED(status) && WEXITSTATUS(status) == kExpectedExitCode;
253
254 // If we fail to support sandboxing, there might be an additional
255 // error message. If so, this was an entirely unexpected and fatal
256 // failure. We should report the failure and somebody must fix
257 // things. This is probably a security-critical bug in the sandboxing
258 // code.
259 if (!rc) {
260 char buf[4096];
261 ssize_t len = HANDLE_EINTR(read(fds[0], buf, sizeof(buf) - 1));
262 if (len > 0) {
263 while (len > 1 && buf[len - 1] == '\n') {
264 --len;
265 }
266 buf[len] = '\000';
267 SANDBOX_DIE(buf);
268 }
269 }
270 if (IGNORE_EINTR(close(fds[0]))) {
271 SANDBOX_DIE("close() failed");
272 }
273
274 return rc;
275 }
276
277 bool SandboxBPF::KernelSupportSeccompBPF() {
278 return RunFunctionInPolicy(ProbeProcess,
279 scoped_ptr<bpf_dsl::Policy>(new ProbePolicy())) &&
280 RunFunctionInPolicy(TryVsyscallProcess,
281 scoped_ptr<bpf_dsl::Policy>(new AllowAllPolicy()));
282 }
283
284 // static
285 SandboxBPF::SandboxStatus SandboxBPF::SupportsSeccompSandbox(int proc_fd) {
286 // It the sandbox is currently active, we clearly must have support for
287 // sandboxing.
288 if (status_ == STATUS_ENABLED) {
289 return status_;
290 }
291
292 // Even if the sandbox was previously available, something might have
293 // changed in our run-time environment. Check one more time.
294 if (status_ == STATUS_AVAILABLE) {
295 if (!IsSingleThreaded(proc_fd)) {
296 status_ = STATUS_UNAVAILABLE;
297 }
298 return status_;
299 }
300
301 if (status_ == STATUS_UNAVAILABLE && IsSingleThreaded(proc_fd)) {
302 // All state transitions resulting in STATUS_UNAVAILABLE are immediately
303 // preceded by STATUS_AVAILABLE. Furthermore, these transitions all
304 // happen, if and only if they are triggered by the process being multi-
305 // threaded.
306 // In other words, if a single-threaded process is currently in the
307 // STATUS_UNAVAILABLE state, it is safe to assume that sandboxing is
308 // actually available.
309 status_ = STATUS_AVAILABLE;
310 return status_;
311 }
312
313 // If we have not previously checked for availability of the sandbox or if
314 // we otherwise don't believe to have a good cached value, we have to
315 // perform a thorough check now.
316 if (status_ == STATUS_UNKNOWN) {
317 // We create our own private copy of a "Sandbox" object. This ensures that
318 // the object does not have any policies configured, that might interfere
319 // with the tests done by "KernelSupportSeccompBPF()".
320 SandboxBPF sandbox;
321
322 // By setting "quiet_ = true" we suppress messages for expected and benign
323 // failures (e.g. if the current kernel lacks support for BPF filters).
324 sandbox.quiet_ = true;
325 sandbox.set_proc_fd(proc_fd);
326 status_ = sandbox.KernelSupportSeccompBPF() ? STATUS_AVAILABLE
327 : STATUS_UNSUPPORTED;
328
329 // As we are performing our tests from a child process, the run-time
330 // environment that is visible to the sandbox is always guaranteed to be
331 // single-threaded. Let's check here whether the caller is single-
332 // threaded. Otherwise, we mark the sandbox as temporarily unavailable.
333 if (status_ == STATUS_AVAILABLE && !IsSingleThreaded(proc_fd)) {
334 status_ = STATUS_UNAVAILABLE;
335 }
336 }
337 return status_;
338 }
339
340 // static
341 SandboxBPF::SandboxStatus
342 SandboxBPF::SupportsSeccompThreadFilterSynchronization() {
343 // Applying NO_NEW_PRIVS, a BPF filter, and synchronizing the filter across
344 // the thread group are all handled atomically by this syscall.
345 const int rv = syscall(
346 __NR_seccomp, SECCOMP_SET_MODE_FILTER, SECCOMP_FILTER_FLAG_TSYNC, NULL);
347
348 if (rv == -1 && errno == EFAULT) {
349 return STATUS_AVAILABLE;
350 } else {
351 // TODO(jln): turn these into DCHECK after 417888 is considered fixed.
352 CHECK_EQ(-1, rv);
353 CHECK(ENOSYS == errno || EINVAL == errno);
354 return STATUS_UNSUPPORTED;
355 }
356 }
357
358 void SandboxBPF::set_proc_fd(int proc_fd) { proc_fd_ = proc_fd; }
359
360 bool SandboxBPF::StartSandbox(SandboxThreadState thread_state) {
361 CHECK(thread_state == PROCESS_SINGLE_THREADED ||
362 thread_state == PROCESS_MULTI_THREADED);
363
364 if (status_ == STATUS_UNSUPPORTED || status_ == STATUS_UNAVAILABLE) {
365 SANDBOX_DIE(
366 "Trying to start sandbox, even though it is known to be "
367 "unavailable");
368 return false;
369 } else if (sandbox_has_started_) {
370 SANDBOX_DIE( 113 SANDBOX_DIE(
371 "Cannot repeatedly start sandbox. Create a separate Sandbox " 114 "Cannot repeatedly start sandbox. Create a separate Sandbox "
372 "object instead."); 115 "object instead.");
373 return false; 116 return false;
374 } 117 }
375 if (proc_fd_ < 0) {
376 proc_fd_ = open("/proc", O_RDONLY | O_DIRECTORY);
377 }
378 if (proc_fd_ < 0) {
379 // For now, continue in degraded mode, if we can't access /proc.
380 // In the future, we might want to tighten this requirement.
381 }
382 118
383 bool supports_tsync = 119 const bool supports_tsync = KernelSupportsSeccompTsync();
384 SupportsSeccompThreadFilterSynchronization() == STATUS_AVAILABLE;
385 120
386 if (thread_state == PROCESS_SINGLE_THREADED) { 121 if (seccomp_level == SeccompLevel::SINGLE_THREADED) {
387 if (!IsSingleThreaded(proc_fd_)) { 122 if (!IsSingleThreaded(proc_task_fd_.get())) {
388 SANDBOX_DIE("Cannot start sandbox; process is already multi-threaded"); 123 SANDBOX_DIE("Cannot start sandbox; process is already multi-threaded");
389 return false; 124 return false;
390 } 125 }
391 } else if (thread_state == PROCESS_MULTI_THREADED) { 126 } else if (seccomp_level == SeccompLevel::MULTI_THREADED) {
392 if (IsSingleThreaded(proc_fd_)) { 127 if (IsSingleThreaded(proc_task_fd_.get())) {
393 SANDBOX_DIE("Cannot start sandbox; " 128 SANDBOX_DIE("Cannot start sandbox; "
394 "process may be single-threaded when reported as not"); 129 "process may be single-threaded when reported as not");
395 return false; 130 return false;
396 } 131 }
397 if (!supports_tsync) { 132 if (!supports_tsync) {
398 SANDBOX_DIE("Cannot start sandbox; kernel does not support synchronizing " 133 SANDBOX_DIE("Cannot start sandbox; kernel does not support synchronizing "
399 "filters for a threadgroup"); 134 "filters for a threadgroup");
400 return false; 135 return false;
401 } 136 }
402 } 137 }
403 138
404 // We no longer need access to any files in /proc. We want to do this 139 // We no longer need access to any files in /proc. We want to do this
405 // before installing the filters, just in case that our policy denies 140 // before installing the filters, just in case that our policy denies
406 // close(). 141 // close().
407 if (proc_fd_ >= 0) { 142 if (proc_task_fd_.is_valid()) {
408 if (IGNORE_EINTR(close(proc_fd_))) { 143 proc_task_fd_.reset();
409 SANDBOX_DIE("Failed to close file descriptor for /proc");
410 return false;
411 }
412 proc_fd_ = -1;
413 } 144 }
414 145
415 // Install the filters. 146 // Install the filters.
416 InstallFilter(supports_tsync || thread_state == PROCESS_MULTI_THREADED); 147 InstallFilter(supports_tsync ||
417 148 seccomp_level == SeccompLevel::MULTI_THREADED);
418 // We are now inside the sandbox.
419 status_ = STATUS_ENABLED;
420 149
421 return true; 150 return true;
422 } 151 }
423 152
424 // Don't take a scoped_ptr here, polymorphism make their use awkward. 153 void SandboxBPF::SetProcTaskFd(base::ScopedFD proc_task_fd) {
425 void SandboxBPF::SetSandboxPolicy(bpf_dsl::Policy* policy) { 154 proc_task_fd_.swap(proc_task_fd);
426 DCHECK(!policy_); 155 }
427 if (sandbox_has_started_) { 156
428 SANDBOX_DIE("Cannot change policy after sandbox has started"); 157 // static
158 bool SandboxBPF::IsValidSyscallNumber(int sysnum) {
159 return SyscallSet::IsValid(sysnum);
160 }
161
162 // static
163 bool SandboxBPF::IsRequiredForUnsafeTrap(int sysno) {
164 return bpf_dsl::PolicyCompiler::IsRequiredForUnsafeTrap(sysno);
165 }
166
167 // static
168 intptr_t SandboxBPF::ForwardSyscall(const struct arch_seccomp_data& args) {
169 return Syscall::Call(
170 args.nr, static_cast<intptr_t>(args.args[0]),
171 static_cast<intptr_t>(args.args[1]), static_cast<intptr_t>(args.args[2]),
172 static_cast<intptr_t>(args.args[3]), static_cast<intptr_t>(args.args[4]),
173 static_cast<intptr_t>(args.args[5]));
174 }
175
176 scoped_ptr<CodeGen::Program> SandboxBPF::AssembleFilter(
177 bool force_verification) {
178 #if !defined(NDEBUG)
179 force_verification = true;
180 #endif
181 DCHECK(policy_);
182 bpf_dsl::PolicyCompiler compiler(policy_.get(), Trap::Registry());
183 scoped_ptr<CodeGen::Program> program = compiler.Compile();
184
185 // Make sure compilation resulted in a BPF program that executes
186 // correctly. Otherwise, there is an internal error in our BPF compiler.
187 // There is really nothing the caller can do until the bug is fixed.
188 if (force_verification) {
189 // Verification is expensive. We only perform this step, if we are
190 // compiled in debug mode, or if the caller explicitly requested
191 // verification.
192
193 const char* err = NULL;
194 if (!Verifier::VerifyBPF(&compiler, *program, *policy_, &err)) {
195 bpf_dsl::DumpBPF::PrintProgram(*program);
196 SANDBOX_DIE(err);
197 }
429 } 198 }
430 policy_.reset(policy); 199
200 return program.Pass();
431 } 201 }
432 202
433 void SandboxBPF::InstallFilter(bool must_sync_threads) { 203 void SandboxBPF::InstallFilter(bool must_sync_threads) {
434 // We want to be very careful in not imposing any requirements on the 204 // We want to be very careful in not imposing any requirements on the
435 // policies that are set with SetSandboxPolicy(). This means, as soon as 205 // policies that are set with SetSandboxPolicy(). This means, as soon as
436 // the sandbox is active, we shouldn't be relying on libraries that could 206 // the sandbox is active, we shouldn't be relying on libraries that could
437 // be making system calls. This, for example, means we should avoid 207 // be making system calls. This, for example, means we should avoid
438 // using the heap and we should avoid using STL functions. 208 // using the heap and we should avoid using STL functions.
439 // Temporarily copy the contents of the "program" vector into a 209 // Temporarily copy the contents of the "program" vector into a
440 // stack-allocated array; and then explicitly destroy that object. 210 // stack-allocated array; and then explicitly destroy that object.
441 // This makes sure we don't ex- or implicitly call new/delete after we 211 // This makes sure we don't ex- or implicitly call new/delete after we
442 // installed the BPF filter program in the kernel. Depending on the 212 // installed the BPF filter program in the kernel. Depending on the
443 // system memory allocator that is in effect, these operators can result 213 // system memory allocator that is in effect, these operators can result
444 // in system calls to things like munmap() or brk(). 214 // in system calls to things like munmap() or brk().
445 CodeGen::Program* program = AssembleFilter(false).release(); 215 CodeGen::Program* program = AssembleFilter(false).release();
446 216
447 struct sock_filter bpf[program->size()]; 217 struct sock_filter bpf[program->size()];
448 const struct sock_fprog prog = {static_cast<unsigned short>(program->size()), 218 const struct sock_fprog prog = {static_cast<unsigned short>(program->size()),
449 bpf}; 219 bpf};
450 memcpy(bpf, &(*program)[0], sizeof(bpf)); 220 memcpy(bpf, &(*program)[0], sizeof(bpf));
451 delete program; 221 delete program;
452 222
453 // Make an attempt to release memory that is no longer needed here, rather 223 // Make an attempt to release memory that is no longer needed here, rather
454 // than in the destructor. Try to avoid as much as possible to presume of 224 // than in the destructor. Try to avoid as much as possible to presume of
455 // what will be possible to do in the new (sandboxed) execution environment. 225 // what will be possible to do in the new (sandboxed) execution environment.
456 policy_.reset(); 226 policy_.reset();
457 227
458 if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) { 228 if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) {
459 SANDBOX_DIE(quiet_ ? NULL : "Kernel refuses to enable no-new-privs"); 229 SANDBOX_DIE("Kernel refuses to enable no-new-privs");
460 } 230 }
461 231
462 // Install BPF filter program. If the thread state indicates multi-threading 232 // Install BPF filter program. If the thread state indicates multi-threading
463 // support, then the kernel hass the seccomp system call. Otherwise, fall 233 // support, then the kernel hass the seccomp system call. Otherwise, fall
464 // back on prctl, which requires the process to be single-threaded. 234 // back on prctl, which requires the process to be single-threaded.
465 if (must_sync_threads) { 235 if (must_sync_threads) {
466 int rv = syscall(__NR_seccomp, SECCOMP_SET_MODE_FILTER, 236 int rv =
467 SECCOMP_FILTER_FLAG_TSYNC, reinterpret_cast<const char*>(&prog)); 237 sys_seccomp(SECCOMP_SET_MODE_FILTER, SECCOMP_FILTER_FLAG_TSYNC, &prog);
468 if (rv) { 238 if (rv) {
469 SANDBOX_DIE(quiet_ ? NULL : 239 SANDBOX_DIE(
470 "Kernel refuses to turn on and synchronize threads for BPF filters"); 240 "Kernel refuses to turn on and synchronize threads for BPF filters");
471 } 241 }
472 } else { 242 } else {
473 if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog)) { 243 if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog)) {
474 SANDBOX_DIE(quiet_ ? NULL : "Kernel refuses to turn on BPF filters"); 244 SANDBOX_DIE("Kernel refuses to turn on BPF filters");
475 } 245 }
476 } 246 }
477 247
478 sandbox_has_started_ = true; 248 sandbox_has_started_ = true;
479 } 249 }
480 250
481 scoped_ptr<CodeGen::Program> SandboxBPF::AssembleFilter(
482 bool force_verification) {
483 #if !defined(NDEBUG)
484 force_verification = true;
485 #endif
486
487 bpf_dsl::PolicyCompiler compiler(policy_.get(), Trap::Registry());
488 scoped_ptr<CodeGen::Program> program = compiler.Compile();
489
490 // Make sure compilation resulted in BPF program that executes
491 // correctly. Otherwise, there is an internal error in our BPF compiler.
492 // There is really nothing the caller can do until the bug is fixed.
493 if (force_verification) {
494 // Verification is expensive. We only perform this step, if we are
495 // compiled in debug mode, or if the caller explicitly requested
496 // verification.
497
498 const char* err = NULL;
499 if (!Verifier::VerifyBPF(&compiler, *program, *policy_, &err)) {
500 bpf_dsl::DumpBPF::PrintProgram(*program);
501 SANDBOX_DIE(err);
502 }
503 }
504
505 return program.Pass();
506 }
507
508 bool SandboxBPF::IsRequiredForUnsafeTrap(int sysno) {
509 return bpf_dsl::PolicyCompiler::IsRequiredForUnsafeTrap(sysno);
510 }
511
512 intptr_t SandboxBPF::ForwardSyscall(const struct arch_seccomp_data& args) {
513 return Syscall::Call(args.nr,
514 static_cast<intptr_t>(args.args[0]),
515 static_cast<intptr_t>(args.args[1]),
516 static_cast<intptr_t>(args.args[2]),
517 static_cast<intptr_t>(args.args[3]),
518 static_cast<intptr_t>(args.args[4]),
519 static_cast<intptr_t>(args.args[5]));
520 }
521
522 SandboxBPF::SandboxStatus SandboxBPF::status_ = STATUS_UNKNOWN;
523
524 } // namespace sandbox 251 } // namespace sandbox
OLDNEW
« no previous file with comments | « sandbox/linux/seccomp-bpf/sandbox_bpf.h ('k') | sandbox/linux/seccomp-bpf/sandbox_bpf_test_runner.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698