OLD | NEW |
---|---|
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 |
OLD | NEW |