Index: sandbox/linux/seccomp-bpf/sandbox_bpf.cc |
diff --git a/sandbox/linux/seccomp-bpf/sandbox_bpf.cc b/sandbox/linux/seccomp-bpf/sandbox_bpf.cc |
index dd6ad94457076bf22c1a02db2d8d2c669e070b8e..73efcfa5660f4bb2186169f80181050f83cfc856 100644 |
--- a/sandbox/linux/seccomp-bpf/sandbox_bpf.cc |
+++ b/sandbox/linux/seccomp-bpf/sandbox_bpf.cc |
@@ -60,11 +60,11 @@ bool Sandbox::RunFunctionInPolicy(void (*CodeInSandbox)(), |
sigset_t oldMask, newMask; |
if (sigfillset(&newMask) || |
sigprocmask(SIG_BLOCK, &newMask, &oldMask)) { |
- die("sigprocmask() failed"); |
+ SANDBOX_DIE("sigprocmask() failed"); |
} |
int fds[2]; |
if (pipe2(fds, O_NONBLOCK|O_CLOEXEC)) { |
- die("pipe() failed"); |
+ SANDBOX_DIE("pipe() failed"); |
} |
pid_t pid = fork(); |
@@ -76,14 +76,14 @@ bool Sandbox::RunFunctionInPolicy(void (*CodeInSandbox)(), |
// attacker might cause fork() to fail at will and could trick us |
// into running without a sandbox. |
sigprocmask(SIG_SETMASK, &oldMask, NULL); // OK, if it fails |
- die("fork() failed unexpectedly"); |
+ SANDBOX_DIE("fork() failed unexpectedly"); |
} |
// In the child process |
if (!pid) { |
// Test a very simple sandbox policy to verify that we can |
// successfully turn on sandboxing. |
- dryRun_ = true; |
+ Die::EnableSimpleExit(); |
if (HANDLE_EINTR(close(fds[0])) || |
dup2(fds[1], 2) != 2 || |
HANDLE_EINTR(close(fds[1]))) { |
@@ -93,29 +93,34 @@ bool Sandbox::RunFunctionInPolicy(void (*CodeInSandbox)(), |
evaluators_.clear(); |
setSandboxPolicy(syscallEvaluator, NULL); |
setProcFd(proc_fd); |
- startSandbox(); |
+ |
+ // By passing "quiet=true" to "startSandboxInternal()" we suppress |
+ // messages for expected and benign failures (e.g. if the current |
+ // kernel lacks support for BPF filters). |
+ startSandboxInternal(true); |
+ |
// Run our code in the sandbox |
CodeInSandbox(); |
} |
- die(NULL); |
+ SANDBOX_DIE(NULL); |
} |
// In the parent process. |
if (HANDLE_EINTR(close(fds[1]))) { |
- die("close() failed"); |
+ SANDBOX_DIE("close() failed"); |
} |
if (sigprocmask(SIG_SETMASK, &oldMask, NULL)) { |
- die("sigprocmask() failed"); |
+ SANDBOX_DIE("sigprocmask() failed"); |
} |
int status; |
if (HANDLE_EINTR(waitpid(pid, &status, 0)) != pid) { |
- die("waitpid() failed unexpectedly"); |
+ SANDBOX_DIE("waitpid() failed unexpectedly"); |
} |
bool rc = WIFEXITED(status) && WEXITSTATUS(status) == 100; |
// If we fail to support sandboxing, there might be an additional |
// error message. If so, this was an entirely unexpected and fatal |
- // failure. We should report the failure and somebody most fix |
+ // failure. We should report the failure and somebody must fix |
// things. This is probably a security-critical bug in the sandboxing |
// code. |
if (!rc) { |
@@ -126,11 +131,11 @@ bool Sandbox::RunFunctionInPolicy(void (*CodeInSandbox)(), |
--len; |
} |
buf[len] = '\000'; |
- die(buf); |
+ SANDBOX_DIE(buf); |
} |
} |
if (HANDLE_EINTR(close(fds[0]))) { |
- die("close() failed"); |
+ SANDBOX_DIE("close() failed"); |
} |
return rc; |
@@ -193,12 +198,13 @@ void Sandbox::setProcFd(int proc_fd) { |
proc_fd_ = proc_fd; |
} |
-void Sandbox::startSandbox() { |
+void Sandbox::startSandboxInternal(bool quiet) { |
if (status_ == STATUS_UNSUPPORTED || status_ == STATUS_UNAVAILABLE) { |
- die("Trying to start sandbox, even though it is known to be unavailable"); |
+ SANDBOX_DIE("Trying to start sandbox, even though it is known to be " |
+ "unavailable"); |
} else if (status_ == STATUS_ENABLED) { |
- die("Cannot start sandbox recursively. Use multiple calls to " |
- "setSandboxPolicy() to stack policies instead"); |
+ SANDBOX_DIE("Cannot start sandbox recursively. Use multiple calls to " |
+ "setSandboxPolicy() to stack policies instead"); |
} |
if (proc_fd_ < 0) { |
proc_fd_ = open("/proc", O_RDONLY|O_DIRECTORY); |
@@ -208,7 +214,7 @@ void Sandbox::startSandbox() { |
// In the future, we might want to tighten this requirement. |
} |
if (!isSingleThreaded(proc_fd_)) { |
- die("Cannot start sandbox, if process is already multi-threaded"); |
+ SANDBOX_DIE("Cannot start sandbox, if process is already multi-threaded"); |
} |
// We no longer need access to any files in /proc. We want to do this |
@@ -216,13 +222,13 @@ void Sandbox::startSandbox() { |
// close(). |
if (proc_fd_ >= 0) { |
if (HANDLE_EINTR(close(proc_fd_))) { |
- die("Failed to close file descriptor for /proc"); |
+ SANDBOX_DIE("Failed to close file descriptor for /proc"); |
} |
proc_fd_ = -1; |
} |
// Install the filters. |
- installFilter(); |
+ installFilter(quiet); |
// We are now inside the sandbox. |
status_ = STATUS_ENABLED; |
@@ -262,7 +268,7 @@ void Sandbox::policySanityChecks(EvaluateSyscall syscallEvaluator, |
// We also have similar checks later, when we actually compile the BPF |
// program. That catches problems with incorrectly stacked evaluators. |
if (!isDenied(syscallEvaluator(-1))) { |
- die("Negative system calls should always be disallowed by policy"); |
+ SANDBOX_DIE("Negative system calls should always be disallowed by policy"); |
} |
#ifndef NDEBUG |
#if defined(__i386__) || defined(__x86_64__) |
@@ -271,7 +277,7 @@ void Sandbox::policySanityChecks(EvaluateSyscall syscallEvaluator, |
sysnum <= (MAX_SYSCALL & ~0x40000000u); |
++sysnum) { |
if (!isDenied(syscallEvaluator(sysnum))) { |
- 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 |
@@ -279,7 +285,7 @@ void Sandbox::policySanityChecks(EvaluateSyscall syscallEvaluator, |
sysnum <= (MAX_SYSCALL | 0x40000000u); |
++sysnum) { |
if (!isDenied(syscallEvaluator(sysnum))) { |
- die("x32 system calls should be explicitly disallowed"); |
+ SANDBOX_DIE("x32 system calls should be explicitly disallowed"); |
} |
} |
#endif |
@@ -293,8 +299,8 @@ void Sandbox::policySanityChecks(EvaluateSyscall syscallEvaluator, |
!isDenied(syscallEvaluator(-1)) || |
!isDenied(syscallEvaluator(static_cast<int>(MIN_SYSCALL) - 1)) || |
!isDenied(syscallEvaluator(static_cast<int>(MAX_SYSCALL) + 1))) { |
- die("Even for default-allow policies, you must never allow system calls " |
- "outside of the standard system call range"); |
+ SANDBOX_DIE("Even for default-allow policies, you must never allow system " |
+ "calls outside of the standard system call range"); |
} |
return; |
} |
@@ -302,17 +308,17 @@ void Sandbox::policySanityChecks(EvaluateSyscall syscallEvaluator, |
void Sandbox::setSandboxPolicy(EvaluateSyscall syscallEvaluator, |
EvaluateArguments argumentEvaluator) { |
if (status_ == STATUS_ENABLED) { |
- die("Cannot change policy after sandbox has started"); |
+ SANDBOX_DIE("Cannot change policy after sandbox has started"); |
} |
policySanityChecks(syscallEvaluator, argumentEvaluator); |
evaluators_.push_back(std::make_pair(syscallEvaluator, argumentEvaluator)); |
} |
-void Sandbox::installFilter() { |
+void Sandbox::installFilter(bool quiet) { |
// Verify that the user pushed a policy. |
if (evaluators_.empty()) { |
filter_failed: |
- die("Failed to configure system call filters"); |
+ SANDBOX_DIE("Failed to configure system call filters"); |
} |
// Set new SIGSYS handler |
@@ -335,13 +341,13 @@ void Sandbox::installFilter() { |
// We can't handle stacked evaluators, yet. We'll get there eventually |
// though. Hang tight. |
if (evaluators_.size() != 1) { |
- die("Not implemented"); |
+ SANDBOX_DIE("Not implemented"); |
} |
// Assemble the BPF filter program. |
Program *program = new Program(); |
if (!program) { |
- die("Out of memory"); |
+ SANDBOX_DIE("Out of memory"); |
} |
// If the architecture doesn't match SECCOMP_ARCH, disallow the |
@@ -396,7 +402,7 @@ void Sandbox::installFilter() { |
#ifndef NDEBUG |
const char *err = NULL; |
if (!Verifier::verifyBPF(*program, evaluators_, &err)) { |
- die(err); |
+ SANDBOX_DIE(err); |
} |
#endif |
@@ -422,10 +428,12 @@ void Sandbox::installFilter() { |
// Install BPF filter program |
if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) { |
- die(dryRun_ ? NULL : "Kernel refuses to enable no-new-privs"); |
+ SANDBOX_DIE(quiet |
+ ? NULL : "Kernel refuses to enable no-new-privs"); |
} else { |
if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog)) { |
- die(dryRun_ ? NULL : "Kernel refuses to turn on BPF filters"); |
+ SANDBOX_DIE(quiet |
+ ? NULL : "Kernel refuses to turn on BPF filters"); |
} |
} |
@@ -463,7 +471,7 @@ void Sandbox::findRanges(Ranges *ranges) { |
if (oldErr != evaluateSyscall(std::numeric_limits<int>::max()) || |
oldErr != evaluateSyscall(std::numeric_limits<int>::min()) || |
oldErr != evaluateSyscall(-1)) { |
- die("Invalid seccomp policy"); |
+ SANDBOX_DIE("Invalid seccomp policy"); |
} |
ranges->push_back( |
Range(oldSysnum, std::numeric_limits<unsigned>::max(), oldErr)); |
@@ -477,7 +485,7 @@ void Sandbox::emitJumpStatements(Program *program, RetInsns *rets, |
// As a sanity check, we need to have at least two distinct ranges for us |
// to be able to build a jump table. |
if (stop - start <= 1) { |
- die("Invalid set of system call ranges"); |
+ SANDBOX_DIE("Invalid set of system call ranges"); |
} |
// Pick the range object that is located at the mid point of our list. |
@@ -488,7 +496,7 @@ void Sandbox::emitJumpStatements(Program *program, RetInsns *rets, |
Program::size_type jmp = program->size(); |
if (jmp >= SECCOMP_MAX_PROGRAM_SIZE) { |
compiler_err: |
- die("Internal compiler error; failed to compile jump table"); |
+ SANDBOX_DIE("Internal compiler error; failed to compile jump table"); |
} |
program->push_back((struct sock_filter) |
BPF_JUMP(BPF_JMP+BPF_JGE+BPF_K, mid->from, |
@@ -542,7 +550,7 @@ void Sandbox::emitReturnStatements(Program *program, const RetInsns& rets) { |
++ret_iter) { |
Program::size_type ip = program->size(); |
if (ip >= SECCOMP_MAX_PROGRAM_SIZE) { |
- die("Internal compiler error; failed to compile jump table"); |
+ SANDBOX_DIE("Internal compiler error; failed to compile jump table"); |
} |
program->push_back((struct sock_filter) |
BPF_STMT(BPF_RET+BPF_K, ret_iter->first)); |
@@ -555,7 +563,7 @@ void Sandbox::emitReturnStatements(Program *program, const RetInsns& rets) { |
// Jumps are always relative and they are always forward. |
int distance = ip - insn_iter->addr - 1; |
if (distance < 0 || distance > 255) { |
- die("Internal compiler error; failed to compile jump table"); |
+ SANDBOX_DIE("Internal compiler error; failed to compile jump table"); |
} |
// Decide whether we need to patch up the "true" or the "false" jump |
@@ -576,7 +584,7 @@ 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_) { |
- // die() can call LOG(FATAL). This is not normally async-signal safe |
+ // 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. |
@@ -584,7 +592,7 @@ void Sandbox::sigSys(int nr, siginfo_t *info, void *void_context) { |
// could actually make an argument that spurious SIGSYS should |
// just get silently ignored. TBD |
sigsys_err: |
- die("Unexpected SIGSYS received"); |
+ SANDBOX_DIE("Unexpected SIGSYS received"); |
} |
// Signal handlers should always preserve "errno". Otherwise, we could |
@@ -640,7 +648,7 @@ void Sandbox::sigSys(int nr, siginfo_t *info, void *void_context) { |
} |
intptr_t Sandbox::bpfFailure(const struct arch_seccomp_data&, void *aux) { |
- die(static_cast<char *>(aux)); |
+ SANDBOX_DIE(static_cast<char *>(aux)); |
} |
int Sandbox::getTrapId(Sandbox::TrapFnc fnc, const void *aux) { |
@@ -665,7 +673,7 @@ int Sandbox::getTrapId(Sandbox::TrapFnc fnc, const void *aux) { |
if (id > SECCOMP_RET_DATA) { |
// In practice, this is pretty much impossible to trigger, as there |
// are other kernel limitations that restrict overall BPF program sizes. |
- die("Too many SECCOMP_RET_TRAP callback instances"); |
+ SANDBOX_DIE("Too many SECCOMP_RET_TRAP callback instances"); |
} |
traps_->push_back(ErrorCode(fnc, aux, id)); |
@@ -683,7 +691,6 @@ int Sandbox::getTrapId(Sandbox::TrapFnc fnc, const void *aux) { |
} |
} |
-bool Sandbox::dryRun_ = false; |
Sandbox::SandboxStatus Sandbox::status_ = STATUS_UNKNOWN; |
int Sandbox::proc_fd_ = -1; |
Sandbox::Evaluators Sandbox::evaluators_; |