| 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 bool supports_tsync = |
| 462 SANDBOX_DIE("Cannot start sandbox, if process is already multi-threaded"); | 485 SupportsSeccompThreadFilterSynchronization() == STATUS_AVAILABLE; |
| 463 return false; | 486 |
| 487 if (thread_state == PROCESS_SINGLE_THREADED) { |
| 488 if (!IsSingleThreaded(proc_fd_)) { |
| 489 SANDBOX_DIE("Cannot start sandbox; process is already multi-threaded"); |
| 490 return false; |
| 491 } |
| 492 } else if (thread_state == PROCESS_MULTI_THREADED) { |
| 493 if (IsSingleThreaded(proc_fd_)) { |
| 494 SANDBOX_DIE("Cannot start sandbox; " |
| 495 "process may be single-threaded when reported as not"); |
| 496 return false; |
| 497 } |
| 498 if (!supports_tsync) { |
| 499 SANDBOX_DIE("Cannot start sandbox; kernel does not support synchronizing " |
| 500 "filters for a threadgroup"); |
| 501 return false; |
| 502 } |
| 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; |
| 473 } | 512 } |
| 474 proc_fd_ = -1; | 513 proc_fd_ = -1; |
| 475 } | 514 } |
| 476 | 515 |
| 477 // Install the filters. | 516 // Install the filters. |
| 478 InstallFilter(thread_state); | 517 InstallFilter(supports_tsync || thread_state == PROCESS_MULTI_THREADED); |
| 479 | 518 |
| 480 // We are now inside the sandbox. | 519 // We are now inside the sandbox. |
| 481 status_ = STATUS_ENABLED; | 520 status_ = STATUS_ENABLED; |
| 482 | 521 |
| 483 return true; | 522 return true; |
| 484 } | 523 } |
| 485 | 524 |
| 486 void SandboxBPF::PolicySanityChecks(SandboxBPFPolicy* policy) { | 525 void SandboxBPF::PolicySanityChecks(SandboxBPFPolicy* policy) { |
| 487 if (!IsDenied(policy->InvalidSyscall(this))) { | 526 if (!IsDenied(policy->InvalidSyscall(this))) { |
| 488 SANDBOX_DIE("Policies should deny invalid system calls."); | 527 SANDBOX_DIE("Policies should deny invalid system calls."); |
| 489 } | 528 } |
| 490 return; | 529 return; |
| 491 } | 530 } |
| 492 | 531 |
| 493 // Don't take a scoped_ptr here, polymorphism make their use awkward. | 532 // Don't take a scoped_ptr here, polymorphism make their use awkward. |
| 494 void SandboxBPF::SetSandboxPolicy(SandboxBPFPolicy* policy) { | 533 void SandboxBPF::SetSandboxPolicy(SandboxBPFPolicy* policy) { |
| 495 DCHECK(!policy_); | 534 DCHECK(!policy_); |
| 496 if (sandbox_has_started_ || !conds_) { | 535 if (sandbox_has_started_ || !conds_) { |
| 497 SANDBOX_DIE("Cannot change policy after sandbox has started"); | 536 SANDBOX_DIE("Cannot change policy after sandbox has started"); |
| 498 } | 537 } |
| 499 PolicySanityChecks(policy); | 538 PolicySanityChecks(policy); |
| 500 policy_.reset(policy); | 539 policy_.reset(policy); |
| 501 } | 540 } |
| 502 | 541 |
| 503 void SandboxBPF::InstallFilter(SandboxThreadState thread_state) { | 542 void SandboxBPF::InstallFilter(bool must_sync_threads) { |
| 504 // We want to be very careful in not imposing any requirements on the | 543 // We want to be very careful in not imposing any requirements on the |
| 505 // policies that are set with SetSandboxPolicy(). This means, as soon as | 544 // policies that are set with SetSandboxPolicy(). This means, as soon as |
| 506 // the sandbox is active, we shouldn't be relying on libraries that could | 545 // the sandbox is active, we shouldn't be relying on libraries that could |
| 507 // be making system calls. This, for example, means we should avoid | 546 // be making system calls. This, for example, means we should avoid |
| 508 // using the heap and we should avoid using STL functions. | 547 // using the heap and we should avoid using STL functions. |
| 509 // Temporarily copy the contents of the "program" vector into a | 548 // Temporarily copy the contents of the "program" vector into a |
| 510 // stack-allocated array; and then explicitly destroy that object. | 549 // stack-allocated array; and then explicitly destroy that object. |
| 511 // This makes sure we don't ex- or implicitly call new/delete after we | 550 // This makes sure we don't ex- or implicitly call new/delete after we |
| 512 // installed the BPF filter program in the kernel. Depending on the | 551 // installed the BPF filter program in the kernel. Depending on the |
| 513 // system memory allocator that is in effect, these operators can result | 552 // system memory allocator that is in effect, these operators can result |
| 514 // in system calls to things like munmap() or brk(). | 553 // in system calls to things like munmap() or brk(). |
| 515 Program* program = AssembleFilter(false /* force_verification */); | 554 Program* program = AssembleFilter(false /* force_verification */); |
| 516 | 555 |
| 517 struct sock_filter bpf[program->size()]; | 556 struct sock_filter bpf[program->size()]; |
| 518 const struct sock_fprog prog = {static_cast<unsigned short>(program->size()), | 557 const struct sock_fprog prog = {static_cast<unsigned short>(program->size()), |
| 519 bpf}; | 558 bpf}; |
| 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 (must_sync_threads) { |
| 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 Loading... |
| 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 |
| OLD | NEW |