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

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

Issue 290223002: Remove SandboxBPF's dependency on CompatibilityPolicy (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fix demo.cc Created 6 years, 7 months 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 | Annotate | Revision Log
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> 14 #include <fcntl.h>
15 #include <string.h> 15 #include <string.h>
16 #include <sys/prctl.h> 16 #include <sys/prctl.h>
17 #include <sys/stat.h> 17 #include <sys/stat.h>
18 #include <sys/syscall.h> 18 #include <sys/syscall.h>
19 #include <sys/types.h> 19 #include <sys/types.h>
20 #include <time.h> 20 #include <time.h>
21 #include <unistd.h> 21 #include <unistd.h>
22 22
23 #include "base/compiler_specific.h" 23 #include "base/compiler_specific.h"
24 #include "base/logging.h" 24 #include "base/logging.h"
25 #include "base/memory/scoped_ptr.h" 25 #include "base/memory/scoped_ptr.h"
26 #include "base/posix/eintr_wrapper.h" 26 #include "base/posix/eintr_wrapper.h"
27 #include "sandbox/linux/seccomp-bpf/codegen.h" 27 #include "sandbox/linux/seccomp-bpf/codegen.h"
28 #include "sandbox/linux/seccomp-bpf/sandbox_bpf_compatibility_policy.h"
29 #include "sandbox/linux/seccomp-bpf/sandbox_bpf_policy.h" 28 #include "sandbox/linux/seccomp-bpf/sandbox_bpf_policy.h"
30 #include "sandbox/linux/seccomp-bpf/syscall.h" 29 #include "sandbox/linux/seccomp-bpf/syscall.h"
31 #include "sandbox/linux/seccomp-bpf/syscall_iterator.h" 30 #include "sandbox/linux/seccomp-bpf/syscall_iterator.h"
32 #include "sandbox/linux/seccomp-bpf/verifier.h" 31 #include "sandbox/linux/seccomp-bpf/verifier.h"
33 32
34 namespace sandbox { 33 namespace sandbox {
35 34
36 namespace { 35 namespace {
37 36
38 const int kExpectedExitCode = 100; 37 const int kExpectedExitCode = 100;
(...skipping 11 matching lines...) Expand all
50 "Failed to set up stderr: "; 49 "Failed to set up stderr: ";
51 if (HANDLE_EINTR(write(out_fd, msg, sizeof(msg) - 1)) > 0 && error_string && 50 if (HANDLE_EINTR(write(out_fd, msg, sizeof(msg) - 1)) > 0 && error_string &&
52 HANDLE_EINTR(write(out_fd, error_string, strlen(error_string))) > 0 && 51 HANDLE_EINTR(write(out_fd, error_string, strlen(error_string))) > 0 &&
53 HANDLE_EINTR(write(out_fd, "\n", 1))) { 52 HANDLE_EINTR(write(out_fd, "\n", 1))) {
54 } 53 }
55 } 54 }
56 #endif // !defined(NDEBUG) 55 #endif // !defined(NDEBUG)
57 56
58 // We define a really simple sandbox policy. It is just good enough for us 57 // We define a really simple sandbox policy. It is just good enough for us
59 // to tell that the sandbox has actually been activated. 58 // to tell that the sandbox has actually been activated.
60 ErrorCode ProbeEvaluator(SandboxBPF*, int sysnum, void*) __attribute__((const)); 59 class ProbePolicy : public SandboxBPFPolicy {
61 ErrorCode ProbeEvaluator(SandboxBPF*, int sysnum, void*) { 60 public:
62 switch (sysnum) { 61 virtual ErrorCode EvaluateSyscall(SandboxBPF*, int sysnum) const OVERRIDE {
63 case __NR_getpid: 62 switch (sysnum) {
64 // Return EPERM so that we can check that the filter actually ran. 63 case __NR_getpid:
65 return ErrorCode(EPERM); 64 // Return EPERM so that we can check that the filter actually ran.
66 case __NR_exit_group: 65 return ErrorCode(EPERM);
67 // Allow exit() with a non-default return code. 66 case __NR_exit_group:
68 return ErrorCode(ErrorCode::ERR_ALLOWED); 67 // Allow exit() with a non-default return code.
69 default: 68 return ErrorCode(ErrorCode::ERR_ALLOWED);
70 // Make everything else fail in an easily recognizable way. 69 default:
71 return ErrorCode(EINVAL); 70 // Make everything else fail in an easily recognizable way.
71 return ErrorCode(EINVAL);
72 }
72 } 73 }
73 } 74 };
74 75
75 void ProbeProcess(void) { 76 void ProbeProcess(void) {
76 if (syscall(__NR_getpid) < 0 && errno == EPERM) { 77 if (syscall(__NR_getpid) < 0 && errno == EPERM) {
77 syscall(__NR_exit_group, static_cast<intptr_t>(kExpectedExitCode)); 78 syscall(__NR_exit_group, static_cast<intptr_t>(kExpectedExitCode));
78 } 79 }
79 } 80 }
80 81
81 ErrorCode AllowAllEvaluator(SandboxBPF*, int sysnum, void*) { 82 class AllowAllPolicy : public SandboxBPFPolicy {
82 DCHECK(SandboxBPF::IsValidSyscallNumber(sysnum)); 83 public:
83 return ErrorCode(ErrorCode::ERR_ALLOWED); 84 virtual ErrorCode EvaluateSyscall(SandboxBPF*, int sysnum) const OVERRIDE {
84 } 85 DCHECK(SandboxBPF::IsValidSyscallNumber(sysnum));
86 return ErrorCode(ErrorCode::ERR_ALLOWED);
87 }
88 };
85 89
86 void TryVsyscallProcess(void) { 90 void TryVsyscallProcess(void) {
87 time_t current_time; 91 time_t current_time;
88 // time() is implemented as a vsyscall. With an older glibc, with 92 // time() is implemented as a vsyscall. With an older glibc, with
89 // vsyscall=emulate and some versions of the seccomp BPF patch 93 // vsyscall=emulate and some versions of the seccomp BPF patch
90 // we may get SIGKILL-ed. Detect this! 94 // we may get SIGKILL-ed. Detect this!
91 if (time(&current_time) != static_cast<time_t>(-1)) { 95 if (time(&current_time) != static_cast<time_t>(-1)) {
92 syscall(__NR_exit_group, static_cast<intptr_t>(kExpectedExitCode)); 96 syscall(__NR_exit_group, static_cast<intptr_t>(kExpectedExitCode));
93 } 97 }
94 } 98 }
(...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after
232 if (conds_) { 236 if (conds_) {
233 delete conds_; 237 delete conds_;
234 } 238 }
235 } 239 }
236 240
237 bool SandboxBPF::IsValidSyscallNumber(int sysnum) { 241 bool SandboxBPF::IsValidSyscallNumber(int sysnum) {
238 return SyscallIterator::IsValid(sysnum); 242 return SyscallIterator::IsValid(sysnum);
239 } 243 }
240 244
241 bool SandboxBPF::RunFunctionInPolicy(void (*code_in_sandbox)(), 245 bool SandboxBPF::RunFunctionInPolicy(void (*code_in_sandbox)(),
242 EvaluateSyscall syscall_evaluator, 246 scoped_ptr<SandboxBPFPolicy> policy) {
243 void* aux) {
244 // Block all signals before forking a child process. This prevents an 247 // Block all signals before forking a child process. This prevents an
245 // attacker from manipulating our test by sending us an unexpected signal. 248 // attacker from manipulating our test by sending us an unexpected signal.
246 sigset_t old_mask, new_mask; 249 sigset_t old_mask, new_mask;
247 if (sigfillset(&new_mask) || sigprocmask(SIG_BLOCK, &new_mask, &old_mask)) { 250 if (sigfillset(&new_mask) || sigprocmask(SIG_BLOCK, &new_mask, &old_mask)) {
248 SANDBOX_DIE("sigprocmask() failed"); 251 SANDBOX_DIE("sigprocmask() failed");
249 } 252 }
250 int fds[2]; 253 int fds[2];
251 if (pipe2(fds, O_NONBLOCK | O_CLOEXEC)) { 254 if (pipe2(fds, O_NONBLOCK | O_CLOEXEC)) {
252 SANDBOX_DIE("pipe() failed"); 255 SANDBOX_DIE("pipe() failed");
253 } 256 }
254 257
255 if (fds[0] <= 2 || fds[1] <= 2) { 258 if (fds[0] <= 2 || fds[1] <= 2) {
256 SANDBOX_DIE("Process started without standard file descriptors"); 259 SANDBOX_DIE("Process started without standard file descriptors");
257 } 260 }
258 261
259 // This code is using fork() and should only ever run single-threaded. 262 // This code is using fork() and should only ever run single-threaded.
260 // Most of the code below is "async-signal-safe" and only minor changes 263 // Most of the code below is "async-signal-safe" and only minor changes
261 // would be needed to support threads. 264 // would be needed to support threads.
jln (very slow on Chromium) 2014/05/19 20:57:19 It's still true that we can enable forking with th
mdempsky 2014/05/19 21:01:28 Noted. I'll look into this as a followup cleanup.
262 DCHECK(IsSingleThreaded(proc_fd_)); 265 DCHECK(IsSingleThreaded(proc_fd_));
263 pid_t pid = fork(); 266 pid_t pid = fork();
264 if (pid < 0) { 267 if (pid < 0) {
265 // Die if we cannot fork(). We would probably fail a little later 268 // Die if we cannot fork(). We would probably fail a little later
266 // anyway, as the machine is likely very close to running out of 269 // anyway, as the machine is likely very close to running out of
267 // memory. 270 // memory.
268 // But what we don't want to do is return "false", as a crafty 271 // But what we don't want to do is return "false", as a crafty
269 // attacker might cause fork() to fail at will and could trick us 272 // attacker might cause fork() to fail at will and could trick us
270 // into running without a sandbox. 273 // into running without a sandbox.
271 sigprocmask(SIG_SETMASK, &old_mask, NULL); // OK, if it fails 274 sigprocmask(SIG_SETMASK, &old_mask, NULL); // OK, if it fails
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
303 } 306 }
304 if (IGNORE_EINTR(close(fds[1]))) { 307 if (IGNORE_EINTR(close(fds[1]))) {
305 // This call to close() has been failing in strange ways. See 308 // This call to close() has been failing in strange ways. See
306 // crbug.com/152530. So we only fail in debug mode now. 309 // crbug.com/152530. So we only fail in debug mode now.
307 #if !defined(NDEBUG) 310 #if !defined(NDEBUG)
308 WriteFailedStderrSetupMessage(fds[1]); 311 WriteFailedStderrSetupMessage(fds[1]);
309 SANDBOX_DIE(NULL); 312 SANDBOX_DIE(NULL);
310 #endif 313 #endif
311 } 314 }
312 315
313 SetSandboxPolicyDeprecated(syscall_evaluator, aux); 316 SetSandboxPolicy(policy.release());
314 if (!StartSandbox(PROCESS_SINGLE_THREADED)) { 317 if (!StartSandbox(PROCESS_SINGLE_THREADED)) {
315 SANDBOX_DIE(NULL); 318 SANDBOX_DIE(NULL);
316 } 319 }
317 320
318 // Run our code in the sandbox. 321 // Run our code in the sandbox.
319 code_in_sandbox(); 322 code_in_sandbox();
320 323
321 // code_in_sandbox() is not supposed to return here. 324 // code_in_sandbox() is not supposed to return here.
322 SANDBOX_DIE(NULL); 325 SANDBOX_DIE(NULL);
323 } 326 }
(...skipping 28 matching lines...) Expand all
352 } 355 }
353 } 356 }
354 if (IGNORE_EINTR(close(fds[0]))) { 357 if (IGNORE_EINTR(close(fds[0]))) {
355 SANDBOX_DIE("close() failed"); 358 SANDBOX_DIE("close() failed");
356 } 359 }
357 360
358 return rc; 361 return rc;
359 } 362 }
360 363
361 bool SandboxBPF::KernelSupportSeccompBPF() { 364 bool SandboxBPF::KernelSupportSeccompBPF() {
362 return RunFunctionInPolicy(ProbeProcess, ProbeEvaluator, 0) && 365 return RunFunctionInPolicy(ProbeProcess,
363 RunFunctionInPolicy(TryVsyscallProcess, AllowAllEvaluator, 0); 366 scoped_ptr<SandboxBPFPolicy>(new ProbePolicy())) &&
367 RunFunctionInPolicy(
368 TryVsyscallProcess,
369 scoped_ptr<SandboxBPFPolicy>(new AllowAllPolicy()));
364 } 370 }
365 371
366 SandboxBPF::SandboxStatus SandboxBPF::SupportsSeccompSandbox(int proc_fd) { 372 SandboxBPF::SandboxStatus SandboxBPF::SupportsSeccompSandbox(int proc_fd) {
367 // It the sandbox is currently active, we clearly must have support for 373 // It the sandbox is currently active, we clearly must have support for
368 // sandboxing. 374 // sandboxing.
369 if (status_ == STATUS_ENABLED) { 375 if (status_ == STATUS_ENABLED) {
370 return status_; 376 return status_;
371 } 377 }
372 378
373 // Even if the sandbox was previously available, something might have 379 // Even if the sandbox was previously available, something might have
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after
468 return true; 474 return true;
469 } 475 }
470 476
471 void SandboxBPF::PolicySanityChecks(SandboxBPFPolicy* policy) { 477 void SandboxBPF::PolicySanityChecks(SandboxBPFPolicy* policy) {
472 if (!IsDenied(policy->InvalidSyscall(this))) { 478 if (!IsDenied(policy->InvalidSyscall(this))) {
473 SANDBOX_DIE("Policies should deny invalid system calls."); 479 SANDBOX_DIE("Policies should deny invalid system calls.");
474 } 480 }
475 return; 481 return;
476 } 482 }
477 483
478 // Deprecated API, supported with a wrapper to the new API.
479 void SandboxBPF::SetSandboxPolicyDeprecated(EvaluateSyscall syscall_evaluator,
480 void* aux) {
481 if (sandbox_has_started_ || !conds_) {
482 SANDBOX_DIE("Cannot change policy after sandbox has started");
483 }
484 SetSandboxPolicy(new CompatibilityPolicy<void>(syscall_evaluator, aux));
485 }
486
487 // Don't take a scoped_ptr here, polymorphism make their use awkward. 484 // Don't take a scoped_ptr here, polymorphism make their use awkward.
488 void SandboxBPF::SetSandboxPolicy(SandboxBPFPolicy* policy) { 485 void SandboxBPF::SetSandboxPolicy(SandboxBPFPolicy* policy) {
489 DCHECK(!policy_); 486 DCHECK(!policy_);
490 if (sandbox_has_started_ || !conds_) { 487 if (sandbox_has_started_ || !conds_) {
491 SANDBOX_DIE("Cannot change policy after sandbox has started"); 488 SANDBOX_DIE("Cannot change policy after sandbox has started");
492 } 489 }
493 PolicySanityChecks(policy); 490 PolicySanityChecks(policy);
494 policy_.reset(policy); 491 policy_.reset(policy);
495 } 492 }
496 493
(...skipping 523 matching lines...) Expand 10 before | Expand all | Expand 10 after
1020 &*conds_->insert(failed).first); 1017 &*conds_->insert(failed).first);
1021 } 1018 }
1022 1019
1023 ErrorCode SandboxBPF::Kill(const char* msg) { 1020 ErrorCode SandboxBPF::Kill(const char* msg) {
1024 return Trap(BPFFailure, const_cast<char*>(msg)); 1021 return Trap(BPFFailure, const_cast<char*>(msg));
1025 } 1022 }
1026 1023
1027 SandboxBPF::SandboxStatus SandboxBPF::status_ = STATUS_UNKNOWN; 1024 SandboxBPF::SandboxStatus SandboxBPF::status_ = STATUS_UNKNOWN;
1028 1025
1029 } // namespace sandbox 1026 } // namespace sandbox
OLDNEW
« no previous file with comments | « sandbox/linux/seccomp-bpf/sandbox_bpf.h ('k') | sandbox/linux/seccomp-bpf/sandbox_bpf_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698