summaryrefslogtreecommitdiffstats
path: root/sandbox
diff options
context:
space:
mode:
authormarkus@chromium.org <markus@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-01-11 16:17:58 +0000
committermarkus@chromium.org <markus@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-01-11 16:17:58 +0000
commitc9cd220761b7ed7950b78a7e64e754f43fbb9ffc (patch)
tree696286d07863b98b2eacc8032faf996ac1750870 /sandbox
parentf8d865534ff053b4c87973968f01755beba9119d (diff)
downloadchromium_src-c9cd220761b7ed7950b78a7e64e754f43fbb9ffc.zip
chromium_src-c9cd220761b7ed7950b78a7e64e754f43fbb9ffc.tar.gz
chromium_src-c9cd220761b7ed7950b78a7e64e754f43fbb9ffc.tar.bz2
If the kernel lacks support for BPF filtering, we can still perform a couple
of static tests on our filter policy and on the filter program. This extends the test coverage of our unittests, even if it is still somewhat limited. TEST=sandbox_linux_unittests BUG=141545 Review URL: https://chromiumcodereview.appspot.com/11829013 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@176361 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'sandbox')
-rw-r--r--sandbox/linux/seccomp-bpf/Makefile2
-rw-r--r--sandbox/linux/seccomp-bpf/bpf_tests.h10
-rw-r--r--sandbox/linux/seccomp-bpf/sandbox_bpf.cc135
-rw-r--r--sandbox/linux/seccomp-bpf/sandbox_bpf.h46
4 files changed, 108 insertions, 85 deletions
diff --git a/sandbox/linux/seccomp-bpf/Makefile b/sandbox/linux/seccomp-bpf/Makefile
index 6d644b8..78ff704 100644
--- a/sandbox/linux/seccomp-bpf/Makefile
+++ b/sandbox/linux/seccomp-bpf/Makefile
@@ -1,5 +1,5 @@
DEF_CFLAGS = -g -O3 -Wall -Werror -Wextra -Wno-missing-field-initializers -fPIC -I.
-DEF_CPPFLAGS = -D_GNU_SOURCE -DSECCOMP_BPF_STANDALONE -DSECCOMP_BPF_VALGRIND_HACKS -include valgrind/valgrind.h -iquote ../../..
+DEF_CPPFLAGS = -D_GNU_SOURCE -DSECCOMP_BPF_STANDALONE -iquote ../../..
DEF_LDFLAGS = -g -lpthread
DEPFLAGS = -MMD -MF .$@.d
MODS := demo sandbox_bpf basicblock codegen die errorcode syscall syscall_iterator util verifier
diff --git a/sandbox/linux/seccomp-bpf/bpf_tests.h b/sandbox/linux/seccomp-bpf/bpf_tests.h
index 3ac631c..931a39e 100644
--- a/sandbox/linux/seccomp-bpf/bpf_tests.h
+++ b/sandbox/linux/seccomp-bpf/bpf_tests.h
@@ -87,9 +87,13 @@ class BpfTests : public UnitTests {
arg->test()(arg->aux_);
} else {
- // TODO(markus): (crbug.com/141545) Call the compiler and verify the
- // policy. That's the least we can do, if we don't have kernel support.
- playground2::Sandbox::SetSandboxPolicy(arg->policy(), NULL);
+ // Call the compiler and verify the policy. That's the least we can do,
+ // if we don't have kernel support.
+ playground2::Sandbox::SetSandboxPolicy(arg->policy(), &arg->aux_);
+ playground2::Sandbox::Program *program =
+ playground2::Sandbox::AssembleFilter();
+ playground2::Sandbox::VerifyProgram(*program);
+ delete program;
sandbox::UnitTests::IgnoreThisTest();
}
}
diff --git a/sandbox/linux/seccomp-bpf/sandbox_bpf.cc b/sandbox/linux/seccomp-bpf/sandbox_bpf.cc
index 366706f..cc2ce1e 100644
--- a/sandbox/linux/seccomp-bpf/sandbox_bpf.cc
+++ b/sandbox/linux/seccomp-bpf/sandbox_bpf.cc
@@ -235,15 +235,6 @@ bool Sandbox::RunFunctionInPolicy(void (*code_in_sandbox)(),
}
bool Sandbox::KernelSupportSeccompBPF(int proc_fd) {
-#if defined(SECCOMP_BPF_VALGRIND_HACKS)
- if (RUNNING_ON_VALGRIND) {
- // Valgrind doesn't like our run-time test. Disable testing and assume we
- // always support sandboxing. This feature should only ever be enabled when
- // debugging.
- return true;
- }
-#endif
-
return
RunFunctionInPolicy(ProbeProcess, Sandbox::ProbeEvaluator, 0, proc_fd) &&
RunFunctionInPolicy(TryVsyscallProcess, Sandbox::AllowAllEvaluator, 0,
@@ -426,6 +417,49 @@ void Sandbox::SetSandboxPolicy(EvaluateSyscall syscall_evaluator, void *aux) {
}
void Sandbox::InstallFilter(bool quiet) {
+ // 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
+ // be making system calls. This, for example, means we should avoid
+ // using the heap and we should avoid using STL functions.
+ // Temporarily copy the contents of the "program" vector into a
+ // stack-allocated array; and then explicitly destroy that object.
+ // This makes sure we don't ex- or implicitly call new/delete after we
+ // installed the BPF filter program in the kernel. Depending on the
+ // system memory allocator that is in effect, these operators can result
+ // in system calls to things like munmap() or brk().
+ Program *program = AssembleFilter();
+
+ // Make sure compilation resulted in BPF program that executes
+ // correctly. Otherwise, there is an internal error in our BPF compiler.
+ // There is really nothing the caller can do until the bug is fixed.
+#ifndef NDEBUG
+ VerifyProgram(*program);
+#endif
+
+ struct sock_filter bpf[program->size()];
+ const struct sock_fprog prog = {
+ static_cast<unsigned short>(program->size()), bpf };
+ memcpy(bpf, &(*program)[0], sizeof(bpf));
+ delete program;
+
+ // Release memory that is no longer needed
+ evaluators_.clear();
+ conds_.clear();
+
+ // Install BPF filter program
+ if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) {
+ SANDBOX_DIE(quiet ? NULL : "Kernel refuses to enable no-new-privs");
+ } else {
+ if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog)) {
+ SANDBOX_DIE(quiet ? NULL : "Kernel refuses to turn on BPF filters");
+ }
+ }
+
+ return;
+}
+
+Sandbox::Program *Sandbox::AssembleFilter() {
// Verify that the user pushed a policy.
if (evaluators_.empty()) {
filter_failed:
@@ -586,68 +620,25 @@ void Sandbox::InstallFilter(bool quiet) {
gen->Compile(head, program);
delete gen;
- // Make sure compilation resulted in BPF program that executes
- // correctly. Otherwise, there is an internal error in our BPF compiler.
- // There is really nothing the caller can do until the bug is fixed.
-#ifndef NDEBUG
- {
- // If we previously rewrote the BPF program so that it calls user-space
- // whenever we return an "errno" value from the filter, then we have to
- // wrap our system call evaluator to perform the same operation. Otherwise,
- // the verifier would also report a mismatch in return codes.
- Evaluators redirected_evaluators;
- redirected_evaluators.push_back(
- std::make_pair(RedirectToUserspaceEvalWrapper, &evaluators_));
-
- const char *err = NULL;
- if (!Verifier::VerifyBPF(
- *program,
- has_unsafe_traps_ ? redirected_evaluators : evaluators_,
- &err)) {
- SANDBOX_DIE(err);
- }
- }
-#endif
-
- // 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
- // be making system calls. This, for example, means we should avoid
- // using the heap and we should avoid using STL functions.
- // Temporarily copy the contents of the "program" vector into a
- // stack-allocated array; and then explicitly destroy that object.
- // This makes sure we don't ex- or implicitly call new/delete after we
- // installed the BPF filter program in the kernel. Depending on the
- // system memory allocator that is in effect, these operators can result
- // in system calls to things like munmap() or brk().
- struct sock_filter bpf[program->size()];
- const struct sock_fprog prog = {
- static_cast<unsigned short>(program->size()), bpf };
- memcpy(bpf, &(*program)[0], sizeof(bpf));
- delete program;
+ return program;
+}
- // Release memory that is no longer needed
- evaluators_.clear();
- conds_.clear();
+void Sandbox::VerifyProgram(const Program& program) {
+ // If we previously rewrote the BPF program so that it calls user-space
+ // whenever we return an "errno" value from the filter, then we have to
+ // wrap our system call evaluator to perform the same operation. Otherwise,
+ // the verifier would also report a mismatch in return codes.
+ Evaluators redirected_evaluators;
+ redirected_evaluators.push_back(
+ std::make_pair(RedirectToUserspaceEvalWrapper, &evaluators_));
-#if defined(SECCOMP_BPF_VALGRIND_HACKS)
- // Valgrind is really not happy about our sandbox. Disable it when running
- // in Valgrind. This feature is dangerous and should never be enabled by
- // default. We protect it behind a pre-processor option.
- if (!RUNNING_ON_VALGRIND)
-#endif
- {
- // Install BPF filter program
- if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) {
- SANDBOX_DIE(quiet ? NULL : "Kernel refuses to enable no-new-privs");
- } else {
- if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog)) {
- SANDBOX_DIE(quiet ? NULL : "Kernel refuses to turn on BPF filters");
- }
- }
+ const char *err = NULL;
+ if (!Verifier::VerifyBPF(
+ program,
+ has_unsafe_traps_ ? redirected_evaluators : evaluators_,
+ &err)) {
+ SANDBOX_DIE(err);
}
-
- return;
}
void Sandbox::FindRanges(Ranges *ranges) {
@@ -706,11 +697,11 @@ Instruction *Sandbox::AssembleJumpTable(CodeGen *gen,
return gen->MakeInstruction(BPF_JMP+BPF_JGE+BPF_K, mid->from, jt, jf);
}
-Instruction *Sandbox::RetExpression(CodeGen *gen, const ErrorCode& cond) {
- if (cond.error_type_ == ErrorCode::ET_COND) {
- return CondExpression(gen, cond);
+Instruction *Sandbox::RetExpression(CodeGen *gen, const ErrorCode& err) {
+ if (err.error_type_ == ErrorCode::ET_COND) {
+ return CondExpression(gen, err);
} else {
- return gen->MakeInstruction(BPF_RET+BPF_K, cond);
+ return gen->MakeInstruction(BPF_RET+BPF_K, err);
}
}
diff --git a/sandbox/linux/seccomp-bpf/sandbox_bpf.h b/sandbox/linux/seccomp-bpf/sandbox_bpf.h
index aee03fa..e440840 100644
--- a/sandbox/linux/seccomp-bpf/sandbox_bpf.h
+++ b/sandbox/linux/seccomp-bpf/sandbox_bpf.h
@@ -46,12 +46,6 @@
#include "base/posix/eintr_wrapper.h"
#endif
-#if defined(SECCOMP_BPF_VALGRIND_HACKS)
-#if !defined(SECCOMP_BPF_STANDALONE)
-#include "base/third_party/valgrind/valgrind.h"
-#endif
-#endif
-
// The Seccomp2 kernel ABI is not part of older versions of glibc.
// As we can't break compilation with these versions of the library,
@@ -298,6 +292,10 @@ class Sandbox {
typedef ErrorCode (*EvaluateSyscall)(int sysnum, void *aux);
typedef std::vector<std::pair<EvaluateSyscall, void *> >Evaluators;
+ // A vector of BPF instructions that need to be installed as a filter
+ // program in the kernel.
+ typedef std::vector<struct sock_filter> Program;
+
// Checks whether a particular system call number is valid on the current
// architecture. E.g. on ARM there's a non-contiguous range of private
// system calls.
@@ -380,6 +378,17 @@ class Sandbox {
// enters Seccomp mode.
static void StartSandbox() { StartSandboxInternal(false); }
+ // Assembles a BPF filter program from the current policy. After calling this
+ // function, you must not call any other sandboxing function.
+ // Typically, AssembleFilter() is only used by unit tests and by sandbox
+ // internals. It should not be used by production code.
+ static Program *AssembleFilter();
+
+ // 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
+ // by the sandbox internals. It should not be used by production code.
+ static void VerifyProgram(const Program& program);
+
private:
friend class CodeGen;
friend class SandboxUnittestHelper;
@@ -387,8 +396,6 @@ class Sandbox {
friend class Util;
friend class Verifier;
- typedef std::vector<struct sock_filter> Program;
-
struct Range {
Range(uint32_t f, uint32_t t, const ErrorCode& e)
: from(f),
@@ -451,12 +458,33 @@ class Sandbox {
// evaluator.
static ErrorCode RedirectToUserspaceEvalWrapper(int sysnum, void *aux);
+ // Assembles and installs a filter based on the policy that has previously
+ // been configured with SetSandboxPolicy().
static void InstallFilter(bool quiet);
+
+ // Finds all the ranges of system calls that need to be handled. Ranges are
+ // sorted in ascending order of system call numbers. There are no gaps in the
+ // ranges. System calls with identical ErrorCodes are coalesced into a single
+ // range.
static void FindRanges(Ranges *ranges);
+
+ // Returns a BPF program snippet that implements a jump table for the
+ // given range of system call numbers. This function runs recursively.
static Instruction *AssembleJumpTable(CodeGen *gen,
Ranges::const_iterator start,
Ranges::const_iterator stop);
- static Instruction *RetExpression(CodeGen *gen, const ErrorCode& cond);
+
+ // Returns a BPF program snippet that makes the BPF filter program exit
+ // with the given ErrorCode "err". N.B. the ErrorCode may very well be a
+ // conditional expression; if so, this function will recursively call
+ // CondExpression() and possibly RetExpression() to build a complex set of
+ // instructions.
+ static Instruction *RetExpression(CodeGen *gen, const ErrorCode& err);
+
+ // Returns a BPF program that evaluates the conditional expression in
+ // "cond" and returns the appropriate value from the BPF filter program.
+ // This function recursively calls RetExpression(); it should only ever be
+ // called from RetExpression().
static Instruction *CondExpression(CodeGen *gen, const ErrorCode& cond);
// Returns the fatal ErrorCode that is used to indicate that somebody