diff options
Diffstat (limited to 'sandbox')
-rw-r--r-- | sandbox/linux/seccomp-bpf/sandbox_bpf.cc | 63 | ||||
-rw-r--r-- | sandbox/linux/seccomp-bpf/sandbox_bpf.h | 21 |
2 files changed, 65 insertions, 19 deletions
diff --git a/sandbox/linux/seccomp-bpf/sandbox_bpf.cc b/sandbox/linux/seccomp-bpf/sandbox_bpf.cc index 56931d1..5f7d028 100644 --- a/sandbox/linux/seccomp-bpf/sandbox_bpf.cc +++ b/sandbox/linux/seccomp-bpf/sandbox_bpf.cc @@ -31,6 +31,10 @@ bool Sandbox::kernelSupportSeccompBPF(int proc_fd) { sigprocmask(SIG_BLOCK, &newMask, &oldMask)) { die("sigprocmask() failed"); } + int fds[2]; + if (pipe2(fds, O_NONBLOCK|O_CLOEXEC)) { + die("pipe() failed"); + } pid_t pid = fork(); if (pid < 0) { @@ -48,18 +52,28 @@ bool Sandbox::kernelSupportSeccompBPF(int proc_fd) { if (!pid) { // Test a very simple sandbox policy to verify that we can // successfully turn on sandboxing. - suppressLogging_ = true; - evaluators_.clear(); - setSandboxPolicy(probeEvaluator, NULL); - setProcFd(proc_fd); - startSandbox(); - if (syscall(__NR_getpid) < 0 && errno == EPERM) { - syscall(__NR_exit_group, (intptr_t)100); + dryRun_ = true; + if (HANDLE_EINTR(close(fds[0])) || + dup2(fds[1], 2) != 2 || + HANDLE_EINTR(close(fds[1]))) { + static const char msg[] = "Failed to set up stderr\n"; + (void)HANDLE_EINTR(write(fds[1], msg, sizeof(msg)-1)); + } else { + evaluators_.clear(); + setSandboxPolicy(probeEvaluator, NULL); + setProcFd(proc_fd); + startSandbox(); + if (syscall(__NR_getpid) < 0 && errno == EPERM) { + syscall(__NR_exit_group, (intptr_t)100); + } } die(NULL); } // In the parent process + if (HANDLE_EINTR(close(fds[1]))) { + die("close() failed"); + } if (sigprocmask(SIG_SETMASK, &oldMask, NULL)) { die("sigprocmask() failed"); } @@ -67,7 +81,29 @@ bool Sandbox::kernelSupportSeccompBPF(int proc_fd) { if (HANDLE_EINTR(waitpid(pid, &status, 0)) != pid) { die("waitpid() failed unexpectedly"); } - return WIFEXITED(status) && WEXITSTATUS(status) == 100; + 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 + // things. This is probably a security-critical bug in the sandboxing + // code. + if (!rc) { + char buf[4096]; + ssize_t len = HANDLE_EINTR(read(fds[0], buf, sizeof(buf) - 1)); + if (len > 0) { + while (len > 1 && buf[len-1] == '\n') { + --len; + } + buf[len] = '\000'; + die(buf); + } + } + if (HANDLE_EINTR(close(fds[0]))) { + die("close() failed"); + } + + return rc; } Sandbox::SandboxStatus Sandbox::supportsSeccompSandbox(int proc_fd) { @@ -312,9 +348,12 @@ void Sandbox::installFilter() { delete program; // Install BPF filter program - if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) || - prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog)) { - goto filter_failed; + if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) { + die(dryRun_ ? 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"); + } } return; @@ -351,7 +390,7 @@ void Sandbox::sigSys(int nr, siginfo_t *info, void *void_context) { } -bool Sandbox::suppressLogging_ = false; +bool Sandbox::dryRun_ = false; Sandbox::SandboxStatus Sandbox::status_ = STATUS_UNKNOWN; int Sandbox::proc_fd_ = -1; std::vector<std::pair<Sandbox::EvaluateSyscall, diff --git a/sandbox/linux/seccomp-bpf/sandbox_bpf.h b/sandbox/linux/seccomp-bpf/sandbox_bpf.h index 82e4656..9a50798 100644 --- a/sandbox/linux/seccomp-bpf/sandbox_bpf.h +++ b/sandbox/linux/seccomp-bpf/sandbox_bpf.h @@ -190,12 +190,9 @@ class Sandbox { protected: // Print an error message and terminate the program. Used for fatal errors. static void die(const char *msg) __attribute__((noreturn)) { - if (!suppressLogging_) { - if (msg) { -#ifdef SECCOMP_BPF_STANDALONE - HANDLE_EINTR(write(2, msg, strlen(msg))); - HANDLE_EINTR(write(2, "\n", 1)); -#else + if (msg) { +#ifndef SECCOMP_BPF_STANDALONE + if (!dryRun_) { // LOG(FATAL) is not neccessarily async-signal safe. It would be // better to always use the code for the SECCOMP_BPF_STANDALONE case. // But that prevents the logging and reporting infrastructure from @@ -204,7 +201,17 @@ class Sandbox { // LOG(FATAL). In the long run, we probably want to rewrite this code // to be async-signal safe. LOG(FATAL) << msg; + } else #endif + { + // If there is no logging infrastructure in place, we just write error + // messages to stderr. + // We also write to stderr, if we are called in a child process from + // supportsSeccompSandbox(). This makes sure we can actually do the + // correct logging from the parent process, which is more likely to + // have access to logging infrastructure. + HANDLE_EINTR(write(2, msg, strlen(msg))); + HANDLE_EINTR(write(2, "\n", 1)); } } for (;;) { @@ -233,7 +240,7 @@ class Sandbox { static void installFilter(); static void sigSys(int nr, siginfo_t *info, void *void_context); - static bool suppressLogging_; + static bool dryRun_; static SandboxStatus status_; static int proc_fd_; static std::vector<std::pair<EvaluateSyscall, |