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

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: Address comments Created 6 years, 4 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)
452 return STATUS_AVAILABLE;
453
454 // errno is probably ENOSYS, indicating the system call is not available.
455 DPCHECK(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 (SupportsSeccompThreadFilterSynchronization() == STATUS_AVAILABLE) {
462 SANDBOX_DIE("Cannot start sandbox, if process is already multi-threaded"); 485 // The kernel supports the seccomp system call, so use that code path.
463 return false; 486 thread_state = PROCESS_MULTI_THREADED;
487 } else {
488 // The kernel doesn't support the seccomp system call, so the process
489 // must not be multi-threaded.
490 if (!IsSingleThreaded(proc_fd_) || thread_state == PROCESS_MULTI_THREADED) {
491 SANDBOX_DIE("Cannot start sandbox, if process is already multi-threaded");
492 return false;
493 }
464 } 494 }
465 495
466 // We no longer need access to any files in /proc. We want to do this 496 // 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 497 // before installing the filters, just in case that our policy denies
468 // close(). 498 // close().
469 if (proc_fd_ >= 0) { 499 if (proc_fd_ >= 0) {
470 if (IGNORE_EINTR(close(proc_fd_))) { 500 if (IGNORE_EINTR(close(proc_fd_))) {
471 SANDBOX_DIE("Failed to close file descriptor for /proc"); 501 SANDBOX_DIE("Failed to close file descriptor for /proc");
472 return false; 502 return false;
473 } 503 }
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
520 memcpy(bpf, &(*program)[0], sizeof(bpf)); 550 memcpy(bpf, &(*program)[0], sizeof(bpf));
521 delete program; 551 delete program;
522 552
523 // Make an attempt to release memory that is no longer needed here, rather 553 // 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 554 // 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. 555 // what will be possible to do in the new (sandboxed) execution environment.
526 delete conds_; 556 delete conds_;
527 conds_ = NULL; 557 conds_ = NULL;
528 policy_.reset(); 558 policy_.reset();
529 559
530 // Install BPF filter program
531 if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) { 560 if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) {
532 SANDBOX_DIE(quiet_ ? NULL : "Kernel refuses to enable no-new-privs"); 561 SANDBOX_DIE(quiet_ ? NULL : "Kernel refuses to enable no-new-privs");
562 }
563
564 // Install BPF filter program. If the thread state indicates multi-threading
565 // support, then the kernel hass the seccomp system call. Otherwise, fall
566 // back on prctl, which requires the process to be single-threaded.
567 if (thread_state == PROCESS_MULTI_THREADED) {
568 int rv = syscall(__NR_seccomp, SECCOMP_SET_MODE_FILTER,
569 SECCOMP_FILTER_FLAG_TSYNC, (const char*)&prog);
570 if (rv) {
571 SANDBOX_DIE(quiet_ ? NULL :
572 "Kernel refuses to turn on and synchronize threads for BPF filters");
573 }
533 } else { 574 } else {
534 if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog)) { 575 if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog)) {
535 SANDBOX_DIE(quiet_ ? NULL : "Kernel refuses to turn on BPF filters"); 576 SANDBOX_DIE(quiet_ ? NULL : "Kernel refuses to turn on BPF filters");
536 } 577 }
537 } 578 }
538 579
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; 580 sandbox_has_started_ = true;
556 } 581 }
557 582
558 SandboxBPF::Program* SandboxBPF::AssembleFilter(bool force_verification) { 583 SandboxBPF::Program* SandboxBPF::AssembleFilter(bool force_verification) {
559 #if !defined(NDEBUG) 584 #if !defined(NDEBUG)
560 force_verification = true; 585 force_verification = true;
561 #endif 586 #endif
562 587
563 // Verify that the user pushed a policy. 588 // Verify that the user pushed a policy.
564 DCHECK(policy_); 589 DCHECK(policy_);
(...skipping 460 matching lines...) Expand 10 before | Expand all | Expand 10 after
1025 &*conds_->insert(failed).first); 1050 &*conds_->insert(failed).first);
1026 } 1051 }
1027 1052
1028 ErrorCode SandboxBPF::Kill(const char* msg) { 1053 ErrorCode SandboxBPF::Kill(const char* msg) {
1029 return Trap(BPFFailure, const_cast<char*>(msg)); 1054 return Trap(BPFFailure, const_cast<char*>(msg));
1030 } 1055 }
1031 1056
1032 SandboxBPF::SandboxStatus SandboxBPF::status_ = STATUS_UNKNOWN; 1057 SandboxBPF::SandboxStatus SandboxBPF::status_ = STATUS_UNKNOWN;
1033 1058
1034 } // namespace sandbox 1059 } // namespace sandbox
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698