diff options
author | markus@chromium.org <markus@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-08-31 06:33:33 +0000 |
---|---|---|
committer | markus@chromium.org <markus@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-08-31 06:33:33 +0000 |
commit | 4321b18bf08725bd21026ffc4f65bccd842810b3 (patch) | |
tree | 878eaf2b15112b393a7d7bbf45b29c2c2dadcc38 /sandbox/linux/seccomp-bpf/sandbox_bpf.cc | |
parent | 5d13e7a4e1d4424daa4ecd2ef4431bece617cd30 (diff) | |
download | chromium_src-4321b18bf08725bd21026ffc4f65bccd842810b3.zip chromium_src-4321b18bf08725bd21026ffc4f65bccd842810b3.tar.gz chromium_src-4321b18bf08725bd21026ffc4f65bccd842810b3.tar.bz2 |
Refactored ErrorCode into it's own class. Removed operators and made them
explicit functions. Added code that allows testing of the sandbox infrastructure
with Valgrind (this currently only works when building with the Makefile; we
still need to decide if and how we want to expose this to our unittests).
Added a way to unittest the ErrorCode class.
BUG=n/a
TEST=sandbox_linux_unittests
Review URL: https://chromiumcodereview.appspot.com/10833044
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@154397 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'sandbox/linux/seccomp-bpf/sandbox_bpf.cc')
-rw-r--r-- | sandbox/linux/seccomp-bpf/sandbox_bpf.cc | 109 |
1 files changed, 66 insertions, 43 deletions
diff --git a/sandbox/linux/seccomp-bpf/sandbox_bpf.cc b/sandbox/linux/seccomp-bpf/sandbox_bpf.cc index 73efcfa..f7c8511 100644 --- a/sandbox/linux/seccomp-bpf/sandbox_bpf.cc +++ b/sandbox/linux/seccomp-bpf/sandbox_bpf.cc @@ -14,17 +14,17 @@ namespace playground2 { // We define a really simple sandbox policy. It is just good enough for us // to tell that the sandbox has actually been activated. -Sandbox::ErrorCode Sandbox::probeEvaluator(int signo) { +ErrorCode Sandbox::probeEvaluator(int signo) { switch (signo) { case __NR_getpid: // Return EPERM so that we can check that the filter actually ran. - return EPERM; + return ErrorCode(EPERM); case __NR_exit_group: // Allow exit() with a non-default return code. - return SB_ALLOWED; + return ErrorCode(ErrorCode::ERR_ALLOWED); default: // Make everything else fail in an easily recognizable way. - return EINVAL; + return ErrorCode(EINVAL); } } @@ -34,12 +34,12 @@ void Sandbox::probeProcess(void) { } } -Sandbox::ErrorCode Sandbox::allowAllEvaluator(int signo) { +ErrorCode Sandbox::allowAllEvaluator(int signo) { if (signo < static_cast<int>(MIN_SYSCALL) || signo > static_cast<int>(MAX_SYSCALL)) { - return ENOSYS; + return ErrorCode(ENOSYS); } - return Sandbox::SB_ALLOWED; + return ErrorCode(ErrorCode::ERR_ALLOWED); } void Sandbox::tryVsyscallProcess(void) { @@ -143,6 +143,15 @@ bool Sandbox::RunFunctionInPolicy(void (*CodeInSandbox)(), } 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, proc_fd) && RunFunctionInPolicy(tryVsyscallProcess, Sandbox::allowAllEvaluator, proc_fd); @@ -255,10 +264,10 @@ bool Sandbox::isSingleThreaded(int proc_fd) { return true; } -static bool isDenied(const Sandbox::ErrorCode& code) { - return (code & SECCOMP_RET_ACTION) == SECCOMP_RET_TRAP || - (code >= (SECCOMP_RET_ERRNO + 1) && - code <= (SECCOMP_RET_ERRNO + 4095)); +bool Sandbox::isDenied(const ErrorCode& code) { + return (code.err() & SECCOMP_RET_ACTION) == SECCOMP_RET_TRAP || + (code.err() >= (SECCOMP_RET_ERRNO + ErrorCode::ERR_MIN_ERRNO) && + code.err() <= (SECCOMP_RET_ERRNO + ErrorCode::ERR_MAX_ERRNO)); } void Sandbox::policySanityChecks(EvaluateSyscall syscallEvaluator, @@ -277,7 +286,8 @@ void Sandbox::policySanityChecks(EvaluateSyscall syscallEvaluator, sysnum <= (MAX_SYSCALL & ~0x40000000u); ++sysnum) { if (!isDenied(syscallEvaluator(sysnum))) { - SANDBOX_DIE("In x32 mode, you should not allow any non-x32 system calls"); + SANDBOX_DIE("In x32 mode, you should not allow any non-x32 " + "system calls"); } } #else @@ -359,8 +369,7 @@ void Sandbox::installFilter(bool quiet) { program->push_back((struct sock_filter) BPF_STMT(BPF_RET+BPF_K, - ErrorCode(bpfFailure, - "Invalid audit architecture in BPF filter"))); + Kill("Invalid audit architecture in BPF filter").err())); // Grab the system call number, so that we can implement jump tables. program->push_back((struct sock_filter) @@ -379,8 +388,7 @@ void Sandbox::installFilter(bool quiet) { #endif program->push_back((struct sock_filter) BPF_STMT(BPF_RET+BPF_K, - ErrorCode(bpfFailure, - "Illegal mixing of system call ABIs"))); + Kill("Illegal mixing of system call ABIs").err())); #endif @@ -425,15 +433,22 @@ void Sandbox::installFilter(bool quiet) { // Release memory that is no longer needed evaluators_.clear(); + errMap_.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"); +#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"); + } } } @@ -453,7 +468,7 @@ void Sandbox::findRanges(Ranges *ranges) { sysnum <= MAX_SYSCALL + 1; ++sysnum) { ErrorCode err = evaluateSyscall(static_cast<int>(sysnum)); - if (err != oldErr) { + if (!err.Equals(oldErr)) { ranges->push_back(Range(oldSysnum, sysnum-1, oldErr)); oldSysnum = sysnum; oldErr = err; @@ -468,9 +483,9 @@ void Sandbox::findRanges(Ranges *ranges) { // We don't actually iterate over all possible 2^32 values, though. We just // perform spot checks at the boundaries. // The cases that we test are: 0x7FFFFFFF, 0x80000000, 0xFFFFFFFF. - if (oldErr != evaluateSyscall(std::numeric_limits<int>::max()) || - oldErr != evaluateSyscall(std::numeric_limits<int>::min()) || - oldErr != evaluateSyscall(-1)) { + if (!oldErr.Equals(evaluateSyscall(std::numeric_limits<int>::max())) || + !oldErr.Equals(evaluateSyscall(std::numeric_limits<int>::min())) || + !oldErr.Equals(evaluateSyscall(-1))) { SANDBOX_DIE("Invalid seccomp policy"); } ranges->push_back( @@ -514,7 +529,7 @@ void Sandbox::emitJumpStatements(Program *program, RetInsns *rets, // Since all branches in BPF programs have to be forward branches, we // keep track of our current instruction pointer and then fix up the // branch when we emit the BPF_RET statement in emitReturnStatements(). - (*rets)[start->err].push_back(FixUp(jmp, false)); + (*rets)[start->err.err()].push_back(FixUp(jmp, false)); } else { // Sub-divide the list of ranges and continue recursively. emitJumpStatements(program, rets, start, mid); @@ -526,7 +541,7 @@ void Sandbox::emitJumpStatements(Program *program, RetInsns *rets, // We narrowed things down to a single range object. Remember instruction // pointer and exit code, so that we can patch up the target of the jump // instruction in emitReturnStatements(). - (*rets)[mid->err].push_back(FixUp(jmp, true)); + (*rets)[mid->err.err()].push_back(FixUp(jmp, true)); } else { // We now know where the block of instructions for the "true" comparison // starts. Patch up the jump target of the BPF_JMP instruction that we @@ -584,8 +599,8 @@ void Sandbox::sigSys(int nr, siginfo_t *info, void *void_context) { if (nr != SIGSYS || info->si_code != SYS_SECCOMP || !void_context || info->si_errno <= 0 || static_cast<size_t>(info->si_errno) > trapArraySize_) { - // SANDBOX_DIE() can call LOG(FATAL). This is not normally async-signal safe - // and can lead to bugs. We should eventually implement a different + // SANDBOX_DIE() can call LOG(FATAL). This is not normally async-signal + // safe and can lead to bugs. We should eventually implement a different // logging and reporting mechanism that is safe to be called from // the sigSys() handler. // TODO: If we feel confident that our code otherwise works correctly, we @@ -647,19 +662,16 @@ void Sandbox::sigSys(int nr, siginfo_t *info, void *void_context) { return; } -intptr_t Sandbox::bpfFailure(const struct arch_seccomp_data&, void *aux) { - SANDBOX_DIE(static_cast<char *>(aux)); -} - -int Sandbox::getTrapId(Sandbox::TrapFnc fnc, const void *aux) { +ErrorCode Sandbox::Trap(ErrorCode::TrapFnc fnc, const void *aux) { // Each unique pair of TrapFnc and auxiliary data make up a distinct instance // of a SECCOMP_RET_TRAP. - std::pair<TrapFnc, const void *> key(fnc, aux); + std::pair<ErrorCode::TrapFnc, const void *> key(fnc, aux); TrapIds::const_iterator iter = trapIds_.find(key); + uint16_t id; if (iter != trapIds_.end()) { // We have seen this pair before. Return the same id that we assigned // earlier. - return iter->second; + id = iter->second; } else { // This is a new pair. Remember it and assign a new id. // Please note that we have to store traps in memory that doesn't get @@ -669,12 +681,12 @@ int Sandbox::getTrapId(Sandbox::TrapFnc fnc, const void *aux) { if (!traps_) { traps_ = new Traps(); } - Traps::size_type id = traps_->size() + 1; - if (id > SECCOMP_RET_DATA) { + if (traps_->size() >= SECCOMP_RET_DATA) { // In practice, this is pretty much impossible to trigger, as there // are other kernel limitations that restrict overall BPF program sizes. SANDBOX_DIE("Too many SECCOMP_RET_TRAP callback instances"); } + id = traps_->size() + 1; traps_->push_back(ErrorCode(fnc, aux, id)); trapIds_[key] = id; @@ -687,16 +699,27 @@ int Sandbox::getTrapId(Sandbox::TrapFnc fnc, const void *aux) { // signal handler, where we can safely do so. trapArray_ = &(*traps_)[0]; trapArraySize_ = id; - return id; } + + ErrorCode err = ErrorCode(fnc, aux, id); + return errMap_[err.err()] = err; +} + +intptr_t Sandbox::bpfFailure(const struct arch_seccomp_data&, void *aux) { + SANDBOX_DIE(static_cast<char *>(aux)); +} + +ErrorCode Sandbox::Kill(const char *msg) { + return Trap(bpfFailure, const_cast<char *>(msg)); } Sandbox::SandboxStatus Sandbox::status_ = STATUS_UNKNOWN; int Sandbox::proc_fd_ = -1; Sandbox::Evaluators Sandbox::evaluators_; +Sandbox::ErrMap Sandbox::errMap_; Sandbox::Traps *Sandbox::traps_ = NULL; Sandbox::TrapIds Sandbox::trapIds_; -Sandbox::ErrorCode *Sandbox::trapArray_ = NULL; +ErrorCode *Sandbox::trapArray_ = NULL; size_t Sandbox::trapArraySize_ = 0; } // namespace |