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

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: Assert thread state 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);
jln (very slow on Chromium) 2014/08/21 21:04:42 Let's pass the NULL parameters explicitly. I'm not
Robert Sesek 2014/08/25 17:17:26 Done.
Robert Sesek 2014/08/25 17:49:01 Actually not done, I couldn't get this to work on
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 (thread_state == PROCESS_SINGLE_THREADED) {
462 SANDBOX_DIE("Cannot start sandbox, if process is already multi-threaded"); 485 if (!IsSingleThreaded(proc_fd_)) {
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; "
jln (very slow on Chromium) 2014/08/21 21:04:41 This is fine, but I feel much less strongly about
Robert Sesek 2014/08/25 17:17:26 Done.
492 "process is not multi-threaded when reported as such");
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 }
500 } else {
501 SANDBOX_DIE("NOTREACHED()");
463 return false; 502 return false;
464 } 503 }
465 504
466 // We no longer need access to any files in /proc. We want to do this 505 // 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 506 // before installing the filters, just in case that our policy denies
468 // close(). 507 // close().
469 if (proc_fd_ >= 0) { 508 if (proc_fd_ >= 0) {
470 if (IGNORE_EINTR(close(proc_fd_))) { 509 if (IGNORE_EINTR(close(proc_fd_))) {
471 SANDBOX_DIE("Failed to close file descriptor for /proc"); 510 SANDBOX_DIE("Failed to close file descriptor for /proc");
472 return false; 511 return false;
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
520 memcpy(bpf, &(*program)[0], sizeof(bpf)); 559 memcpy(bpf, &(*program)[0], sizeof(bpf));
521 delete program; 560 delete program;
522 561
523 // Make an attempt to release memory that is no longer needed here, rather 562 // 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 563 // 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. 564 // what will be possible to do in the new (sandboxed) execution environment.
526 delete conds_; 565 delete conds_;
527 conds_ = NULL; 566 conds_ = NULL;
528 policy_.reset(); 567 policy_.reset();
529 568
530 // Install BPF filter program
531 if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) { 569 if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) {
532 SANDBOX_DIE(quiet_ ? NULL : "Kernel refuses to enable no-new-privs"); 570 SANDBOX_DIE(quiet_ ? NULL : "Kernel refuses to enable no-new-privs");
571 }
572
573 // Install BPF filter program. If the thread state indicates multi-threading
574 // support, then the kernel hass the seccomp system call. Otherwise, fall
575 // back on prctl, which requires the process to be single-threaded.
576 if (thread_state == PROCESS_MULTI_THREADED) {
jln (very slow on Chromium) 2014/08/21 21:04:42 It's a very nice safeguard to always use TSYNC and
Robert Sesek 2014/08/25 17:17:26 Done.
577 int rv = syscall(__NR_seccomp, SECCOMP_SET_MODE_FILTER,
578 SECCOMP_FILTER_FLAG_TSYNC, reinterpret_cast<const char*>(&prog));
579 if (rv) {
580 SANDBOX_DIE(quiet_ ? NULL :
581 "Kernel refuses to turn on and synchronize threads for BPF filters");
582 }
533 } else { 583 } else {
534 if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog)) { 584 if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog)) {
535 SANDBOX_DIE(quiet_ ? NULL : "Kernel refuses to turn on BPF filters"); 585 SANDBOX_DIE(quiet_ ? NULL : "Kernel refuses to turn on BPF filters");
536 } 586 }
537 } 587 }
538 588
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; 589 sandbox_has_started_ = true;
556 } 590 }
557 591
558 SandboxBPF::Program* SandboxBPF::AssembleFilter(bool force_verification) { 592 SandboxBPF::Program* SandboxBPF::AssembleFilter(bool force_verification) {
559 #if !defined(NDEBUG) 593 #if !defined(NDEBUG)
560 force_verification = true; 594 force_verification = true;
561 #endif 595 #endif
562 596
563 // Verify that the user pushed a policy. 597 // Verify that the user pushed a policy.
564 DCHECK(policy_); 598 DCHECK(policy_);
(...skipping 460 matching lines...) Expand 10 before | Expand all | Expand 10 after
1025 &*conds_->insert(failed).first); 1059 &*conds_->insert(failed).first);
1026 } 1060 }
1027 1061
1028 ErrorCode SandboxBPF::Kill(const char* msg) { 1062 ErrorCode SandboxBPF::Kill(const char* msg) {
1029 return Trap(BPFFailure, const_cast<char*>(msg)); 1063 return Trap(BPFFailure, const_cast<char*>(msg));
1030 } 1064 }
1031 1065
1032 SandboxBPF::SandboxStatus SandboxBPF::status_ = STATUS_UNKNOWN; 1066 SandboxBPF::SandboxStatus SandboxBPF::status_ = STATUS_UNKNOWN;
1033 1067
1034 } // namespace sandbox 1068 } // namespace sandbox
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698