diff options
author | rsesek@chromium.org <rsesek@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-04-05 02:31:02 +0000 |
---|---|---|
committer | rsesek@chromium.org <rsesek@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-04-05 02:31:02 +0000 |
commit | 4189a3a015f332242a670255adc2beee1b2d6439 (patch) | |
tree | facb9e84fc36912a7e6b84ba49792da21280c6c1 /sandbox | |
parent | e60bc6fa324e2c5653657c5783314a951559cb89 (diff) | |
download | chromium_src-4189a3a015f332242a670255adc2beee1b2d6439.zip chromium_src-4189a3a015f332242a670255adc2beee1b2d6439.tar.gz chromium_src-4189a3a015f332242a670255adc2beee1b2d6439.tar.bz2 |
sandbox: Add support for starting seccomp-bpf with threads.
This requires an experimental kernel patch that has not yet been accepted
upstream. However this is a prerequisite for getting running seccomp-bpf under
Android.
BUG=308763, 308775
Review URL: https://codereview.chromium.org/224403002
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@261951 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'sandbox')
-rw-r--r-- | sandbox/linux/seccomp-bpf/bpf_tests.h | 3 | ||||
-rw-r--r-- | sandbox/linux/seccomp-bpf/demo.cc | 3 | ||||
-rw-r--r-- | sandbox/linux/seccomp-bpf/sandbox_bpf.cc | 40 | ||||
-rw-r--r-- | sandbox/linux/seccomp-bpf/sandbox_bpf.h | 19 | ||||
-rw-r--r-- | sandbox/linux/seccomp-bpf/sandbox_bpf_unittest.cc | 4 |
5 files changed, 56 insertions, 13 deletions
diff --git a/sandbox/linux/seccomp-bpf/bpf_tests.h b/sandbox/linux/seccomp-bpf/bpf_tests.h index dd30b15..cc3fc25 100644 --- a/sandbox/linux/seccomp-bpf/bpf_tests.h +++ b/sandbox/linux/seccomp-bpf/bpf_tests.h @@ -84,7 +84,8 @@ class BPFTests : public UnitTests { sandbox::SandboxBPF sandbox; sandbox.set_proc_fd(proc_fd); sandbox.SetSandboxPolicyDeprecated(arg->policy(), &arg->aux_); - sandbox.SandboxBPF::StartSandbox(); + BPF_ASSERT(sandbox.StartSandbox( + sandbox::SandboxBPF::PROCESS_SINGLE_THREADED)); arg->test()(arg->aux_); } else { diff --git a/sandbox/linux/seccomp-bpf/demo.cc b/sandbox/linux/seccomp-bpf/demo.cc index 1418018..bf5b85a 100644 --- a/sandbox/linux/seccomp-bpf/demo.cc +++ b/sandbox/linux/seccomp-bpf/demo.cc @@ -26,6 +26,7 @@ #include <time.h> #include <unistd.h> +#include "base/logging.h" #include "base/posix/eintr_wrapper.h" #include "sandbox/linux/seccomp-bpf/sandbox_bpf.h" #include "sandbox/linux/services/linux_syscalls.h" @@ -421,7 +422,7 @@ int main(int argc, char *argv[]) { SandboxBPF sandbox; sandbox.set_proc_fd(proc_fd); sandbox.SetSandboxPolicyDeprecated(Evaluator, NULL); - sandbox.StartSandbox(); + CHECK(sandbox.StartSandbox(SandboxBPF::PROCESS_SINGLE_THREADED)); // Check that we can create threads pthread_t thr; diff --git a/sandbox/linux/seccomp-bpf/sandbox_bpf.cc b/sandbox/linux/seccomp-bpf/sandbox_bpf.cc index 6b2327e..1538fe8 100644 --- a/sandbox/linux/seccomp-bpf/sandbox_bpf.cc +++ b/sandbox/linux/seccomp-bpf/sandbox_bpf.cc @@ -323,7 +323,9 @@ bool SandboxBPF::RunFunctionInPolicy(void (*code_in_sandbox)(), } SetSandboxPolicyDeprecated(syscall_evaluator, aux); - StartSandbox(); + if (!StartSandbox(PROCESS_SINGLE_THREADED)) { + SANDBOX_DIE(NULL); + } // Run our code in the sandbox. code_in_sandbox(); @@ -430,15 +432,20 @@ SandboxBPF::SandboxStatus SandboxBPF::SupportsSeccompSandbox(int proc_fd) { void SandboxBPF::set_proc_fd(int proc_fd) { proc_fd_ = proc_fd; } -void SandboxBPF::StartSandbox() { +bool SandboxBPF::StartSandbox(SandboxThreadState thread_state) { + CHECK(thread_state == PROCESS_SINGLE_THREADED || + thread_state == PROCESS_MULTI_THREADED); + if (status_ == STATUS_UNSUPPORTED || status_ == STATUS_UNAVAILABLE) { SANDBOX_DIE( "Trying to start sandbox, even though it is known to be " "unavailable"); + return false; } else if (sandbox_has_started_ || !conds_) { SANDBOX_DIE( "Cannot repeatedly start sandbox. Create a separate Sandbox " "object instead."); + return false; } if (proc_fd_ < 0) { proc_fd_ = open("/proc", O_RDONLY | O_DIRECTORY); @@ -447,8 +454,10 @@ void SandboxBPF::StartSandbox() { // For now, continue in degraded mode, if we can't access /proc. // In the future, we might want to tighten this requirement. } - if (!IsSingleThreaded(proc_fd_)) { + + if (thread_state == PROCESS_SINGLE_THREADED && !IsSingleThreaded(proc_fd_)) { SANDBOX_DIE("Cannot start sandbox, if process is already multi-threaded"); + return false; } // We no longer need access to any files in /proc. We want to do this @@ -457,15 +466,18 @@ void SandboxBPF::StartSandbox() { if (proc_fd_ >= 0) { if (IGNORE_EINTR(close(proc_fd_))) { SANDBOX_DIE("Failed to close file descriptor for /proc"); + return false; } proc_fd_ = -1; } // Install the filters. - InstallFilter(); + InstallFilter(thread_state); // We are now inside the sandbox. status_ = STATUS_ENABLED; + + return true; } void SandboxBPF::PolicySanityChecks(SandboxBPFPolicy* policy) { @@ -499,7 +511,7 @@ void SandboxBPF::SetSandboxPolicy(SandboxBPFPolicy* policy) { policy_.reset(policy); } -void SandboxBPF::InstallFilter() { +void SandboxBPF::InstallFilter(SandboxThreadState thread_state) { // We want to be very careful in not imposing any requirements on the // policies that are set with SetSandboxPolicy(). This means, as soon as // the sandbox is active, we shouldn't be relying on libraries that could @@ -535,9 +547,23 @@ void SandboxBPF::InstallFilter() { } } - sandbox_has_started_ = true; + // TODO(rsesek): Always try to engage the sandbox with the + // PROCESS_MULTI_THREADED path first, and if that fails, assert that the + // process IsSingleThreaded() or SANDBOX_DIE. + + if (thread_state == PROCESS_MULTI_THREADED) { + // TODO(rsesek): Move these to a more reasonable place once the kernel + // patch has landed upstream and these values are formalized. + #define PR_SECCOMP_EXT 41 + #define SECCOMP_EXT_ACT 1 + #define SECCOMP_EXT_ACT_TSYNC 1 + if (prctl(PR_SECCOMP_EXT, SECCOMP_EXT_ACT, SECCOMP_EXT_ACT_TSYNC, 0, 0)) { + SANDBOX_DIE(quiet_ ? NULL : "Kernel refuses to synchronize threadgroup " + "BPF filters."); + } + } - return; + sandbox_has_started_ = true; } SandboxBPF::Program* SandboxBPF::AssembleFilter(bool force_verification) { diff --git a/sandbox/linux/seccomp-bpf/sandbox_bpf.h b/sandbox/linux/seccomp-bpf/sandbox_bpf.h index f6e4135..67b84b9 100644 --- a/sandbox/linux/seccomp-bpf/sandbox_bpf.h +++ b/sandbox/linux/seccomp-bpf/sandbox_bpf.h @@ -16,6 +16,7 @@ #include <utility> #include <vector> +#include "base/compiler_specific.h" #include "base/memory/scoped_ptr.h" #include "sandbox/linux/sandbox_export.h" #include "sandbox/linux/seccomp-bpf/die.h" @@ -52,6 +53,18 @@ class SANDBOX_EXPORT SandboxBPF { STATUS_ENABLED // The sandbox is now active }; + // Depending on the level of kernel support, seccomp-bpf may require the + // process to be single-threaded in order to enable it. When calling + // StartSandbox(), the program should indicate whether or not the sandbox + // should try and engage with multi-thread support. + enum SandboxThreadState { + PROCESS_INVALID, + PROCESS_SINGLE_THREADED, // The program is currently single-threaded. + // Note: PROCESS_MULTI_THREADED requires experimental kernel support that + // has not been contributed to upstream Linux. + PROCESS_MULTI_THREADED, // The program may be multi-threaded. + }; + // When calling setSandboxPolicy(), the caller can provide an arbitrary // pointer in |aux|. This pointer will then be forwarded to the sandbox // policy each time a call is made through an EvaluateSyscall function @@ -168,6 +181,8 @@ class SANDBOX_EXPORT SandboxBPF { // This is the main public entry point. It finds all system calls that // need rewriting, sets up the resources needed by the sandbox, and // enters Seccomp mode. + // The calling process must specify its current SandboxThreadState, as a way + // to tell the sandbox which type of kernel support it should engage. // It is possible to stack multiple sandboxes by creating separate "Sandbox" // objects and calling "StartSandbox()" on each of them. Please note, that // this requires special care, though, as newly stacked sandboxes can never @@ -176,7 +191,7 @@ class SANDBOX_EXPORT SandboxBPF { // disallowed. // Finally, stacking does add more kernel overhead than having a single // combined policy. So, it should only be used if there are no alternatives. - void StartSandbox(); + bool StartSandbox(SandboxThreadState thread_state) WARN_UNUSED_RESULT; // Assembles a BPF filter program from the current policy. After calling this // function, you must not call any other sandboxing function. @@ -229,7 +244,7 @@ class SANDBOX_EXPORT SandboxBPF { // Assembles and installs a filter based on the policy that has previously // been configured with SetSandboxPolicy(). - void InstallFilter(); + void InstallFilter(SandboxThreadState thread_state); // Verify the correctness of a compiled program by comparing it against the // current policy. This function should only ever be called by unit tests and diff --git a/sandbox/linux/seccomp-bpf/sandbox_bpf_unittest.cc b/sandbox/linux/seccomp-bpf/sandbox_bpf_unittest.cc index 17df1d5..ba13a32 100644 --- a/sandbox/linux/seccomp-bpf/sandbox_bpf_unittest.cc +++ b/sandbox/linux/seccomp-bpf/sandbox_bpf_unittest.cc @@ -99,7 +99,7 @@ SANDBOX_TEST(SandboxBPF, DISABLE_ON_TSAN(VerboseAPITesting)) { pid_t test_var = 0; SandboxBPF sandbox; sandbox.SetSandboxPolicyDeprecated(VerboseAPITestingPolicy, &test_var); - sandbox.StartSandbox(); + BPF_ASSERT(sandbox.StartSandbox(SandboxBPF::PROCESS_SINGLE_THREADED)); BPF_ASSERT(test_var == 0); BPF_ASSERT(syscall(__NR_getpid) == 0); @@ -326,7 +326,7 @@ BPF_TEST(SandboxBPF, StackingPolicy, StackingPolicyPartOne) { // restrict filters, but we cannot relax existing filters. SandboxBPF sandbox; sandbox.SetSandboxPolicyDeprecated(StackingPolicyPartTwo, NULL); - sandbox.StartSandbox(); + BPF_ASSERT(sandbox.StartSandbox(SandboxBPF::PROCESS_SINGLE_THREADED)); errno = 0; BPF_ASSERT(syscall(__NR_getppid, 0) == -1); |