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

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: 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 int rv = syscall(__NR_seccomp);
jln (very slow on Chromium) 2014/08/20 21:34:20 Do you want to add a comment saying that synchroni
Robert Sesek 2014/08/21 16:50:18 Done.
442
443 // The system call should have failed with EINVAL.
444 if (rv != -1)
445 return STATUS_UNKNOWN;
jln (very slow on Chromium) 2014/08/20 21:34:20 Maybe add a NOTREACHED() here?
Robert Sesek 2014/08/21 16:50:17 Done.
446
447 if (errno == EINVAL)
448 return STATUS_AVAILABLE;
449
450 // errno is probably ENOSYS, indicating the system call is not available.
451 return STATUS_UNSUPPORTED;
jln (very slow on Chromium) 2014/08/20 21:34:20 DCHECK(ENOSYS == errno) maybe?
Robert Sesek 2014/08/21 16:50:18 Done.
452 }
453
436 void SandboxBPF::set_proc_fd(int proc_fd) { proc_fd_ = proc_fd; } 454 void SandboxBPF::set_proc_fd(int proc_fd) { proc_fd_ = proc_fd; }
437 455
438 bool SandboxBPF::StartSandbox(SandboxThreadState thread_state) { 456 bool SandboxBPF::StartSandbox(SandboxThreadState thread_state) {
439 CHECK(thread_state == PROCESS_SINGLE_THREADED || 457 CHECK(thread_state == PROCESS_SINGLE_THREADED ||
440 thread_state == PROCESS_MULTI_THREADED); 458 thread_state == PROCESS_MULTI_THREADED);
441 459
442 if (status_ == STATUS_UNSUPPORTED || status_ == STATUS_UNAVAILABLE) { 460 if (status_ == STATUS_UNSUPPORTED || status_ == STATUS_UNAVAILABLE) {
443 SANDBOX_DIE( 461 SANDBOX_DIE(
444 "Trying to start sandbox, even though it is known to be " 462 "Trying to start sandbox, even though it is known to be "
445 "unavailable"); 463 "unavailable");
446 return false; 464 return false;
447 } else if (sandbox_has_started_ || !conds_) { 465 } else if (sandbox_has_started_ || !conds_) {
448 SANDBOX_DIE( 466 SANDBOX_DIE(
449 "Cannot repeatedly start sandbox. Create a separate Sandbox " 467 "Cannot repeatedly start sandbox. Create a separate Sandbox "
450 "object instead."); 468 "object instead.");
451 return false; 469 return false;
452 } 470 }
453 if (proc_fd_ < 0) { 471 if (proc_fd_ < 0) {
454 proc_fd_ = open("/proc", O_RDONLY | O_DIRECTORY); 472 proc_fd_ = open("/proc", O_RDONLY | O_DIRECTORY);
455 } 473 }
456 if (proc_fd_ < 0) { 474 if (proc_fd_ < 0) {
jln (very slow on Chromium) 2014/08/20 21:34:20 Ugh I need to get rid of this(always pass a file d
Robert Sesek 2014/08/21 16:50:18 Acknowledged.
457 // For now, continue in degraded mode, if we can't access /proc. 475 // For now, continue in degraded mode, if we can't access /proc.
458 // In the future, we might want to tighten this requirement. 476 // In the future, we might want to tighten this requirement.
459 } 477 }
460 478
461 if (thread_state == PROCESS_SINGLE_THREADED && !IsSingleThreaded(proc_fd_)) { 479 if (SupportsSeccompThreadFilterSynchronization() == STATUS_AVAILABLE) {
462 SANDBOX_DIE("Cannot start sandbox, if process is already multi-threaded"); 480 // The kernel supports the seccomp system call, so use that code path.
463 return false; 481 thread_state = PROCESS_MULTI_THREADED;
jln (very slow on Chromium) 2014/08/20 21:34:20 I would still want us to crash if the caller passe
Robert Sesek 2014/08/21 16:50:18 I actually think SandboxThreadState should just go
jln (very slow on Chromium) 2014/08/21 18:47:09 At a high level, paranoia dictates to carefully as
482 } else {
483 // The kernel doesn't support the seccomp system call, so the process
484 // must not be multi-threaded.
485 if (!IsSingleThreaded(proc_fd_) || thread_state == PROCESS_MULTI_THREADED) {
486 SANDBOX_DIE("Cannot start sandbox, if process is already multi-threaded");
487 return false;
488 }
464 } 489 }
465 490
466 // We no longer need access to any files in /proc. We want to do this 491 // 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 492 // before installing the filters, just in case that our policy denies
468 // close(). 493 // close().
469 if (proc_fd_ >= 0) { 494 if (proc_fd_ >= 0) {
470 if (IGNORE_EINTR(close(proc_fd_))) { 495 if (IGNORE_EINTR(close(proc_fd_))) {
471 SANDBOX_DIE("Failed to close file descriptor for /proc"); 496 SANDBOX_DIE("Failed to close file descriptor for /proc");
472 return false; 497 return false;
473 } 498 }
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
520 memcpy(bpf, &(*program)[0], sizeof(bpf)); 545 memcpy(bpf, &(*program)[0], sizeof(bpf));
521 delete program; 546 delete program;
522 547
523 // Make an attempt to release memory that is no longer needed here, rather 548 // 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 549 // 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. 550 // what will be possible to do in the new (sandboxed) execution environment.
526 delete conds_; 551 delete conds_;
527 conds_ = NULL; 552 conds_ = NULL;
528 policy_.reset(); 553 policy_.reset();
529 554
530 // Install BPF filter program 555 // Install BPF filter program. If the thread state indicates multi-threading
jln (very slow on Chromium) 2014/08/20 21:34:20 Should we still try to enable NO_NEW_PRIV via prct
Robert Sesek 2014/08/21 16:50:18 Done.
531 if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) { 556 // support, then the kernel hass the seccomp system call. Otherwise, fall
532 SANDBOX_DIE(quiet_ ? NULL : "Kernel refuses to enable no-new-privs"); 557 // back on prctl, which requires the process to be single-threaded.
558 if (thread_state == PROCESS_MULTI_THREADED) {
559 int rv = syscall(__NR_seccomp, SECCOMP_SET_MODE_FILTER,
560 SECCOMP_FILTER_FLAG_TSYNC, (const char*)&prog);
561 if (rv) {
562 SANDBOX_DIE(quiet_ ? NULL :
563 "Kernel refuses to turn on and synchronize threads for BPF filters");
564 }
533 } else { 565 } else {
534 if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog)) { 566 if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) {
535 SANDBOX_DIE(quiet_ ? NULL : "Kernel refuses to turn on BPF filters"); 567 SANDBOX_DIE(quiet_ ? NULL : "Kernel refuses to enable no-new-privs");
568 } else {
569 if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog)) {
570 SANDBOX_DIE(quiet_ ? NULL : "Kernel refuses to turn on BPF filters");
571 }
536 } 572 }
537 } 573 }
538 574
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; 575 sandbox_has_started_ = true;
556 } 576 }
557 577
558 SandboxBPF::Program* SandboxBPF::AssembleFilter(bool force_verification) { 578 SandboxBPF::Program* SandboxBPF::AssembleFilter(bool force_verification) {
559 #if !defined(NDEBUG) 579 #if !defined(NDEBUG)
560 force_verification = true; 580 force_verification = true;
561 #endif 581 #endif
562 582
563 // Verify that the user pushed a policy. 583 // Verify that the user pushed a policy.
564 DCHECK(policy_); 584 DCHECK(policy_);
(...skipping 460 matching lines...) Expand 10 before | Expand all | Expand 10 after
1025 &*conds_->insert(failed).first); 1045 &*conds_->insert(failed).first);
1026 } 1046 }
1027 1047
1028 ErrorCode SandboxBPF::Kill(const char* msg) { 1048 ErrorCode SandboxBPF::Kill(const char* msg) {
1029 return Trap(BPFFailure, const_cast<char*>(msg)); 1049 return Trap(BPFFailure, const_cast<char*>(msg));
1030 } 1050 }
1031 1051
1032 SandboxBPF::SandboxStatus SandboxBPF::status_ = STATUS_UNKNOWN; 1052 SandboxBPF::SandboxStatus SandboxBPF::status_ = STATUS_UNKNOWN;
1033 1053
1034 } // namespace sandbox 1054 } // namespace sandbox
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698