diff options
Diffstat (limited to 'sandbox/linux/seccomp-bpf/sandbox_bpf.cc')
-rw-r--r-- | sandbox/linux/seccomp-bpf/sandbox_bpf.cc | 85 |
1 files changed, 23 insertions, 62 deletions
diff --git a/sandbox/linux/seccomp-bpf/sandbox_bpf.cc b/sandbox/linux/seccomp-bpf/sandbox_bpf.cc index bc7e682..643eacb 100644 --- a/sandbox/linux/seccomp-bpf/sandbox_bpf.cc +++ b/sandbox/linux/seccomp-bpf/sandbox_bpf.cc @@ -5,6 +5,7 @@ #include <time.h> #include "sandbox/linux/seccomp-bpf/sandbox_bpf.h" +#include "sandbox/linux/seccomp-bpf/syscall_iterator.h" #include "sandbox/linux/seccomp-bpf/verifier.h" // The kernel gives us a sandbox, we turn it into a playground :-) @@ -34,9 +35,12 @@ void Sandbox::probeProcess(void) { } } -ErrorCode Sandbox::allowAllEvaluator(int signo) { - if (signo < static_cast<int>(MIN_SYSCALL) || - signo > static_cast<int>(MAX_SYSCALL)) { +bool Sandbox::isValidSyscallNumber(int sysnum) { + return SyscallIterator::IsValid(sysnum); +} + +ErrorCode Sandbox::allowAllEvaluator(int sysnum) { + if (!isValidSyscallNumber(sysnum)) { return ErrorCode(ENOSYS); } return ErrorCode(ErrorCode::ERR_ALLOWED); @@ -144,7 +148,6 @@ bool Sandbox::RunFunctionInPolicy(void (*CodeInSandbox)(), } return rc; - } bool Sandbox::kernelSupportSeccompBPF(int proc_fd) { @@ -277,46 +280,13 @@ bool Sandbox::isDenied(const ErrorCode& code) { void Sandbox::policySanityChecks(EvaluateSyscall syscallEvaluator, EvaluateArguments) { - // Do some sanity checks on the policy. This will warn users if they do - // things that are likely unsafe and unintended. - // We also have similar checks later, when we actually compile the BPF - // program. That catches problems with incorrectly stacked evaluators. - if (!isDenied(syscallEvaluator(-1))) { - SANDBOX_DIE("Negative system calls should always be disallowed by policy"); - } -#ifndef NDEBUG -#if defined(__i386__) || defined(__x86_64__) -#if defined(__x86_64__) && defined(__ILP32__) - for (unsigned int sysnum = MIN_SYSCALL & ~0x40000000u; - sysnum <= (MAX_SYSCALL & ~0x40000000u); - ++sysnum) { + for (SyscallIterator iter(true); !iter.Done(); ) { + uint32_t sysnum = iter.Next(); if (!isDenied(syscallEvaluator(sysnum))) { - SANDBOX_DIE("In x32 mode, you should not allow any non-x32 " - "system calls"); + SANDBOX_DIE("Policies should deny system calls that are outside the " + "expected range (typically MIN_SYSCALL..MAX_SYSCALL)"); } } -#else - for (unsigned int sysnum = MIN_SYSCALL | 0x40000000u; - sysnum <= (MAX_SYSCALL | 0x40000000u); - ++sysnum) { - if (!isDenied(syscallEvaluator(sysnum))) { - SANDBOX_DIE("x32 system calls should be explicitly disallowed"); - } - } -#endif -#endif -#endif - // Check interesting boundary values just outside of the valid system call - // range: 0x7FFFFFFF, 0x80000000, 0xFFFFFFFF, MIN_SYSCALL-1, MAX_SYSCALL+1. - // They all should be denied. - if (!isDenied(syscallEvaluator(std::numeric_limits<int>::max())) || - !isDenied(syscallEvaluator(std::numeric_limits<int>::min())) || - !isDenied(syscallEvaluator(-1)) || - !isDenied(syscallEvaluator(static_cast<int>(MIN_SYSCALL) - 1)) || - !isDenied(syscallEvaluator(static_cast<int>(MAX_SYSCALL) + 1))) { - SANDBOX_DIE("Even for default-allow policies, you must never allow system " - "calls outside of the standard system call range"); - } return; } @@ -469,32 +439,23 @@ void Sandbox::findRanges(Ranges *ranges) { EvaluateSyscall evaluateSyscall = evaluators_.begin()->first; uint32_t oldSysnum = 0; ErrorCode oldErr = evaluateSyscall(oldSysnum); - for (uint32_t sysnum = std::max(1u, MIN_SYSCALL); - sysnum <= MAX_SYSCALL + 1; - ++sysnum) { + ErrorCode invalidErr = evaluateSyscall(MIN_SYSCALL - 1); + for (SyscallIterator iter(false); !iter.Done(); ) { + uint32_t sysnum = iter.Next(); ErrorCode err = evaluateSyscall(static_cast<int>(sysnum)); - if (!err.Equals(oldErr)) { - ranges->push_back(Range(oldSysnum, sysnum-1, oldErr)); + if (!iter.IsValid(sysnum) && !invalidErr.Equals(err)) { + // A proper sandbox policy should always treat system calls outside of + // the range MIN_SYSCALL..MAX_SYSCALL (i.e. anything that returns + // "false" for SyscallIterator::IsValid()) identically. Typically, all + // of these system calls would be denied with the same ErrorCode. + SANDBOX_DIE("Invalid seccomp policy"); + } + if (!err.Equals(oldErr) || iter.Done()) { + ranges->push_back(Range(oldSysnum, sysnum - 1, oldErr)); oldSysnum = sysnum; oldErr = err; } } - - // As we looped all the way past the valid system calls (i.e. MAX_SYSCALL+1), - // "oldErr" should at this point be the "default" policy for all system call - // numbers that don't have an explicit handler in the system call evaluator. - // But as we are quite paranoid, we perform some more sanity checks to verify - // that there actually is a consistent "default" policy in the first place. - // 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.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( - Range(oldSysnum, std::numeric_limits<unsigned>::max(), oldErr)); } void Sandbox::emitJumpStatements(Program *program, RetInsns *rets, |