summaryrefslogtreecommitdiffstats
path: root/sandbox/linux/seccomp-bpf/sandbox_bpf.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sandbox/linux/seccomp-bpf/sandbox_bpf.cc')
-rw-r--r--sandbox/linux/seccomp-bpf/sandbox_bpf.cc85
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,