summaryrefslogtreecommitdiffstats
path: root/sandbox
diff options
context:
space:
mode:
authorrsesek@chromium.org <rsesek@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-04-05 02:31:02 +0000
committerrsesek@chromium.org <rsesek@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-04-05 02:31:02 +0000
commit4189a3a015f332242a670255adc2beee1b2d6439 (patch)
treefacb9e84fc36912a7e6b84ba49792da21280c6c1 /sandbox
parente60bc6fa324e2c5653657c5783314a951559cb89 (diff)
downloadchromium_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.h3
-rw-r--r--sandbox/linux/seccomp-bpf/demo.cc3
-rw-r--r--sandbox/linux/seccomp-bpf/sandbox_bpf.cc40
-rw-r--r--sandbox/linux/seccomp-bpf/sandbox_bpf.h19
-rw-r--r--sandbox/linux/seccomp-bpf/sandbox_bpf_unittest.cc4
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);