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

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

Issue 494743003: sandbox: Add support for the new seccomp() system call in kernel 3.17. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Rebase Created 6 years, 3 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
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>
(...skipping 12 matching lines...) Expand all
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/macros.h" 25 #include "base/macros.h"
26 #include "base/memory/scoped_ptr.h" 26 #include "base/memory/scoped_ptr.h"
27 #include "base/posix/eintr_wrapper.h" 27 #include "base/posix/eintr_wrapper.h"
28 #include "sandbox/linux/seccomp-bpf/codegen.h" 28 #include "sandbox/linux/seccomp-bpf/codegen.h"
29 #include "sandbox/linux/seccomp-bpf/sandbox_bpf_policy.h" 29 #include "sandbox/linux/seccomp-bpf/sandbox_bpf_policy.h"
30 #include "sandbox/linux/seccomp-bpf/syscall.h" 30 #include "sandbox/linux/seccomp-bpf/syscall.h"
31 #include "sandbox/linux/seccomp-bpf/syscall_iterator.h" 31 #include "sandbox/linux/seccomp-bpf/syscall_iterator.h"
32 #include "sandbox/linux/seccomp-bpf/verifier.h" 32 #include "sandbox/linux/seccomp-bpf/verifier.h"
33 #include "sandbox/linux/services/linux_syscalls.h"
33 34
34 namespace sandbox { 35 namespace sandbox {
35 36
36 namespace { 37 namespace {
37 38
38 const int kExpectedExitCode = 100; 39 const int kExpectedExitCode = 100;
39 40
40 int popcount(uint32_t x) { 41 int popcount(uint32_t x) {
41 return __builtin_popcount(x); 42 return __builtin_popcount(x);
42 } 43 }
(...skipping 328 matching lines...) Expand 10 before | Expand all | Expand 10 after
371 } 372 }
372 373
373 bool SandboxBPF::KernelSupportSeccompBPF() { 374 bool SandboxBPF::KernelSupportSeccompBPF() {
374 return RunFunctionInPolicy(ProbeProcess, 375 return RunFunctionInPolicy(ProbeProcess,
375 scoped_ptr<SandboxBPFPolicy>(new ProbePolicy())) && 376 scoped_ptr<SandboxBPFPolicy>(new ProbePolicy())) &&
376 RunFunctionInPolicy( 377 RunFunctionInPolicy(
377 TryVsyscallProcess, 378 TryVsyscallProcess,
378 scoped_ptr<SandboxBPFPolicy>(new AllowAllPolicy())); 379 scoped_ptr<SandboxBPFPolicy>(new AllowAllPolicy()));
379 } 380 }
380 381
382 // static
381 SandboxBPF::SandboxStatus SandboxBPF::SupportsSeccompSandbox(int proc_fd) { 383 SandboxBPF::SandboxStatus SandboxBPF::SupportsSeccompSandbox(int proc_fd) {
382 // It the sandbox is currently active, we clearly must have support for 384 // It the sandbox is currently active, we clearly must have support for
383 // sandboxing. 385 // sandboxing.
384 if (status_ == STATUS_ENABLED) { 386 if (status_ == STATUS_ENABLED) {
385 return status_; 387 return status_;
386 } 388 }
387 389
388 // Even if the sandbox was previously available, something might have 390 // Even if the sandbox was previously available, something might have
389 // changed in our run-time environment. Check one more time. 391 // changed in our run-time environment. Check one more time.
390 if (status_ == STATUS_AVAILABLE) { 392 if (status_ == STATUS_AVAILABLE) {
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
426 // environment that is visible to the sandbox is always guaranteed to be 428 // environment that is visible to the sandbox is always guaranteed to be
427 // single-threaded. Let's check here whether the caller is single- 429 // single-threaded. Let's check here whether the caller is single-
428 // threaded. Otherwise, we mark the sandbox as temporarily unavailable. 430 // threaded. Otherwise, we mark the sandbox as temporarily unavailable.
429 if (status_ == STATUS_AVAILABLE && !IsSingleThreaded(proc_fd)) { 431 if (status_ == STATUS_AVAILABLE && !IsSingleThreaded(proc_fd)) {
430 status_ = STATUS_UNAVAILABLE; 432 status_ = STATUS_UNAVAILABLE;
431 } 433 }
432 } 434 }
433 return status_; 435 return status_;
434 } 436 }
435 437
438 // static
439 SandboxBPF::SandboxStatus
440 SandboxBPF::SupportsSeccompThreadFilterSynchronization() {
441 // Applying NO_NEW_PRIVS, a BPF filter, and synchronizing the filter across
442 // the thread group are all handled atomically by this syscall.
443 int rv = syscall(__NR_seccomp);
444
445 // The system call should have failed with EINVAL.
446 if (rv != -1) {
447 NOTREACHED();
448 return STATUS_UNKNOWN;
449 }
450
451 if (errno == EINVAL || errno == EFAULT)
452 return STATUS_AVAILABLE;
453
454 // errno is probably ENOSYS, indicating the system call is not available.
455 DCHECK_EQ(errno, ENOSYS);
456 return STATUS_UNSUPPORTED;
457 }
458
436 void SandboxBPF::set_proc_fd(int proc_fd) { proc_fd_ = proc_fd; } 459 void SandboxBPF::set_proc_fd(int proc_fd) { proc_fd_ = proc_fd; }
437 460
438 bool SandboxBPF::StartSandbox(SandboxThreadState thread_state) { 461 bool SandboxBPF::StartSandbox(SandboxThreadState thread_state) {
439 CHECK(thread_state == PROCESS_SINGLE_THREADED || 462 CHECK(thread_state == PROCESS_SINGLE_THREADED ||
440 thread_state == PROCESS_MULTI_THREADED); 463 thread_state == PROCESS_MULTI_THREADED);
441 464
442 if (status_ == STATUS_UNSUPPORTED || status_ == STATUS_UNAVAILABLE) { 465 if (status_ == STATUS_UNSUPPORTED || status_ == STATUS_UNAVAILABLE) {
443 SANDBOX_DIE( 466 SANDBOX_DIE(
444 "Trying to start sandbox, even though it is known to be " 467 "Trying to start sandbox, even though it is known to be "
445 "unavailable"); 468 "unavailable");
446 return false; 469 return false;
447 } else if (sandbox_has_started_ || !conds_) { 470 } else if (sandbox_has_started_ || !conds_) {
448 SANDBOX_DIE( 471 SANDBOX_DIE(
449 "Cannot repeatedly start sandbox. Create a separate Sandbox " 472 "Cannot repeatedly start sandbox. Create a separate Sandbox "
450 "object instead."); 473 "object instead.");
451 return false; 474 return false;
452 } 475 }
453 if (proc_fd_ < 0) { 476 if (proc_fd_ < 0) {
454 proc_fd_ = open("/proc", O_RDONLY | O_DIRECTORY); 477 proc_fd_ = open("/proc", O_RDONLY | O_DIRECTORY);
455 } 478 }
456 if (proc_fd_ < 0) { 479 if (proc_fd_ < 0) {
457 // For now, continue in degraded mode, if we can't access /proc. 480 // For now, continue in degraded mode, if we can't access /proc.
458 // In the future, we might want to tighten this requirement. 481 // In the future, we might want to tighten this requirement.
459 } 482 }
460 483
461 if (thread_state == PROCESS_SINGLE_THREADED && !IsSingleThreaded(proc_fd_)) { 484 if (thread_state == PROCESS_SINGLE_THREADED) {
462 SANDBOX_DIE("Cannot start sandbox, if process is already multi-threaded"); 485 if (!IsSingleThreaded(proc_fd_)) {
463 return false; 486 SANDBOX_DIE("Cannot start sandbox; process is already multi-threaded");
487 return false;
488 }
489 } else if (thread_state == PROCESS_MULTI_THREADED) {
490 if (IsSingleThreaded(proc_fd_)) {
491 SANDBOX_DIE("Cannot start sandbox; "
492 "process may be single-threaded when reported as not");
493 return false;
494 }
495 if (SupportsSeccompThreadFilterSynchronization() != STATUS_AVAILABLE) {
496 SANDBOX_DIE("Cannot start sandbox; kernel does not support synchronizing "
497 "filters for a threadgroup");
498 return false;
499 }
464 } 500 }
465 501
466 // We no longer need access to any files in /proc. We want to do this 502 // We no longer need access to any files in /proc. We want to do this
467 // before installing the filters, just in case that our policy denies 503 // before installing the filters, just in case that our policy denies
468 // close(). 504 // close().
469 if (proc_fd_ >= 0) { 505 if (proc_fd_ >= 0) {
470 if (IGNORE_EINTR(close(proc_fd_))) { 506 if (IGNORE_EINTR(close(proc_fd_))) {
471 SANDBOX_DIE("Failed to close file descriptor for /proc"); 507 SANDBOX_DIE("Failed to close file descriptor for /proc");
472 return false; 508 return false;
473 } 509 }
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
520 memcpy(bpf, &(*program)[0], sizeof(bpf)); 556 memcpy(bpf, &(*program)[0], sizeof(bpf));
521 delete program; 557 delete program;
522 558
523 // Make an attempt to release memory that is no longer needed here, rather 559 // Make an attempt to release memory that is no longer needed here, rather
524 // than in the destructor. Try to avoid as much as possible to presume of 560 // than in the destructor. Try to avoid as much as possible to presume of
525 // what will be possible to do in the new (sandboxed) execution environment. 561 // what will be possible to do in the new (sandboxed) execution environment.
526 delete conds_; 562 delete conds_;
527 conds_ = NULL; 563 conds_ = NULL;
528 policy_.reset(); 564 policy_.reset();
529 565
530 // Install BPF filter program
531 if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) { 566 if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) {
532 SANDBOX_DIE(quiet_ ? NULL : "Kernel refuses to enable no-new-privs"); 567 SANDBOX_DIE(quiet_ ? NULL : "Kernel refuses to enable no-new-privs");
568 }
569
570 // Install BPF filter program. If the thread state indicates multi-threading
571 // support, then the kernel hass the seccomp system call. Otherwise, fall
572 // back on prctl, which requires the process to be single-threaded.
573 if (SupportsSeccompThreadFilterSynchronization() == STATUS_AVAILABLE) {
jln (very slow on Chromium) 2014/08/25 18:13:49 I worry that if SupportsSeccompThreadFilterSynchro
Robert Sesek 2014/08/25 18:25:14 Done.
574 int rv = syscall(__NR_seccomp, SECCOMP_SET_MODE_FILTER,
575 SECCOMP_FILTER_FLAG_TSYNC, reinterpret_cast<const char*>(&prog));
576 if (rv) {
577 SANDBOX_DIE(quiet_ ? NULL :
578 "Kernel refuses to turn on and synchronize threads for BPF filters");
579 }
533 } else { 580 } else {
534 if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog)) { 581 if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog)) {
535 SANDBOX_DIE(quiet_ ? NULL : "Kernel refuses to turn on BPF filters"); 582 SANDBOX_DIE(quiet_ ? NULL : "Kernel refuses to turn on BPF filters");
536 } 583 }
537 } 584 }
538 585
539 // TODO(rsesek): Always try to engage the sandbox with the
540 // PROCESS_MULTI_THREADED path first, and if that fails, assert that the
541 // process IsSingleThreaded() or SANDBOX_DIE.
542
543 if (thread_state == PROCESS_MULTI_THREADED) {
544 // TODO(rsesek): Move these to a more reasonable place once the kernel
545 // patch has landed upstream and these values are formalized.
546 #define PR_SECCOMP_EXT 41
547 #define SECCOMP_EXT_ACT 1
548 #define SECCOMP_EXT_ACT_TSYNC 1
549 if (prctl(PR_SECCOMP_EXT, SECCOMP_EXT_ACT, SECCOMP_EXT_ACT_TSYNC, 0, 0)) {
550 SANDBOX_DIE(quiet_ ? NULL : "Kernel refuses to synchronize threadgroup "
551 "BPF filters.");
552 }
553 }
554
555 sandbox_has_started_ = true; 586 sandbox_has_started_ = true;
556 } 587 }
557 588
558 SandboxBPF::Program* SandboxBPF::AssembleFilter(bool force_verification) { 589 SandboxBPF::Program* SandboxBPF::AssembleFilter(bool force_verification) {
559 #if !defined(NDEBUG) 590 #if !defined(NDEBUG)
560 force_verification = true; 591 force_verification = true;
561 #endif 592 #endif
562 593
563 // Verify that the user pushed a policy. 594 // Verify that the user pushed a policy.
564 DCHECK(policy_); 595 DCHECK(policy_);
(...skipping 460 matching lines...) Expand 10 before | Expand all | Expand 10 after
1025 &*conds_->insert(failed).first); 1056 &*conds_->insert(failed).first);
1026 } 1057 }
1027 1058
1028 ErrorCode SandboxBPF::Kill(const char* msg) { 1059 ErrorCode SandboxBPF::Kill(const char* msg) {
1029 return Trap(BPFFailure, const_cast<char*>(msg)); 1060 return Trap(BPFFailure, const_cast<char*>(msg));
1030 } 1061 }
1031 1062
1032 SandboxBPF::SandboxStatus SandboxBPF::status_ = STATUS_UNKNOWN; 1063 SandboxBPF::SandboxStatus SandboxBPF::status_ = STATUS_UNKNOWN;
1033 1064
1034 } // namespace sandbox 1065 } // 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