| 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 43c9af6f339be05c5a841da22474b3449144ab17..555f672f4359d140134fab58e696634d504debe7 100644
|
| --- a/sandbox/linux/seccomp-bpf/sandbox_bpf.cc
|
| +++ b/sandbox/linux/seccomp-bpf/sandbox_bpf.cc
|
| @@ -11,24 +11,18 @@
|
| #endif
|
|
|
| #include <errno.h>
|
| -#include <fcntl.h>
|
| #include <linux/filter.h>
|
| -#include <signal.h>
|
| -#include <string.h>
|
| #include <sys/prctl.h>
|
| -#include <sys/stat.h>
|
| -#include <sys/syscall.h>
|
| #include <sys/types.h>
|
| -#include <sys/wait.h>
|
| -#include <time.h>
|
| #include <unistd.h>
|
|
|
| #include "base/compiler_specific.h"
|
| +#include "base/files/scoped_file.h"
|
| #include "base/logging.h"
|
| #include "base/macros.h"
|
| #include "base/memory/scoped_ptr.h"
|
| #include "base/posix/eintr_wrapper.h"
|
| -#include "sandbox/linux/bpf_dsl/bpf_dsl.h"
|
| +#include "base/third_party/valgrind/valgrind.h"
|
| #include "sandbox/linux/bpf_dsl/dump_bpf.h"
|
| #include "sandbox/linux/bpf_dsl/policy.h"
|
| #include "sandbox/linux/bpf_dsl/policy_compiler.h"
|
| @@ -42,354 +36,95 @@
|
| #include "sandbox/linux/seccomp-bpf/verifier.h"
|
| #include "sandbox/linux/services/linux_syscalls.h"
|
| #include "sandbox/linux/services/syscall_wrappers.h"
|
| -
|
| -using sandbox::bpf_dsl::Allow;
|
| -using sandbox::bpf_dsl::Error;
|
| -using sandbox::bpf_dsl::ResultExpr;
|
| +#include "sandbox/linux/services/thread_helpers.h"
|
|
|
| namespace sandbox {
|
|
|
| namespace {
|
|
|
| -const int kExpectedExitCode = 100;
|
| +bool IsRunningOnValgrind() { return RUNNING_ON_VALGRIND; }
|
|
|
| -#if !defined(NDEBUG)
|
| -void WriteFailedStderrSetupMessage(int out_fd) {
|
| - const char* error_string = strerror(errno);
|
| - static const char msg[] =
|
| - "You have reproduced a puzzling issue.\n"
|
| - "Please, report to crbug.com/152530!\n"
|
| - "Failed to set up stderr: ";
|
| - if (HANDLE_EINTR(write(out_fd, msg, sizeof(msg) - 1)) > 0 && error_string &&
|
| - HANDLE_EINTR(write(out_fd, error_string, strlen(error_string))) > 0 &&
|
| - HANDLE_EINTR(write(out_fd, "\n", 1))) {
|
| - }
|
| +bool IsSingleThreaded(int proc_task_fd) {
|
| + return ThreadHelpers::IsSingleThreaded(proc_task_fd);
|
| }
|
| -#endif // !defined(NDEBUG)
|
| -
|
| -// We define a really simple sandbox policy. It is just good enough for us
|
| -// to tell that the sandbox has actually been activated.
|
| -class ProbePolicy : public bpf_dsl::Policy {
|
| - public:
|
| - ProbePolicy() {}
|
| - virtual ~ProbePolicy() {}
|
| -
|
| - virtual ResultExpr EvaluateSyscall(int sysnum) const override {
|
| - switch (sysnum) {
|
| - case __NR_getpid:
|
| - // Return EPERM so that we can check that the filter actually ran.
|
| - return Error(EPERM);
|
| - case __NR_exit_group:
|
| - // Allow exit() with a non-default return code.
|
| - return Allow();
|
| - default:
|
| - // Make everything else fail in an easily recognizable way.
|
| - return Error(EINVAL);
|
| - }
|
| - }
|
|
|
| - private:
|
| - DISALLOW_COPY_AND_ASSIGN(ProbePolicy);
|
| -};
|
| +// Check if the kernel supports seccomp-filter (a.k.a. seccomp mode 2) via
|
| +// prctl().
|
| +bool KernelSupportsSeccompBPF() {
|
| + errno = 0;
|
| + const int rv = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, nullptr);
|
|
|
| -void ProbeProcess(void) {
|
| - if (sys_getpid() < 0 && errno == EPERM) {
|
| - sys_exit_group(kExpectedExitCode);
|
| + if (rv == -1 && EFAULT == errno) {
|
| + return true;
|
| }
|
| + return false;
|
| }
|
|
|
| -class AllowAllPolicy : public bpf_dsl::Policy {
|
| - public:
|
| - AllowAllPolicy() {}
|
| - virtual ~AllowAllPolicy() {}
|
| -
|
| - virtual ResultExpr EvaluateSyscall(int sysnum) const override {
|
| - DCHECK(SandboxBPF::IsValidSyscallNumber(sysnum));
|
| - return Allow();
|
| - }
|
| -
|
| - private:
|
| - DISALLOW_COPY_AND_ASSIGN(AllowAllPolicy);
|
| -};
|
| -
|
| -void TryVsyscallProcess(void) {
|
| - time_t current_time;
|
| - // time() is implemented as a vsyscall. With an older glibc, with
|
| - // vsyscall=emulate and some versions of the seccomp BPF patch
|
| - // we may get SIGKILL-ed. Detect this!
|
| - if (time(¤t_time) != static_cast<time_t>(-1)) {
|
| - sys_exit_group(kExpectedExitCode);
|
| - }
|
| -}
|
| +// Check if the kernel supports seccomp-filter via the seccomp system call
|
| +// and the TSYNC feature to enable seccomp on all threads.
|
| +bool KernelSupportsSeccompTsync() {
|
| + errno = 0;
|
| + const int rv =
|
| + sys_seccomp(SECCOMP_SET_MODE_FILTER, SECCOMP_FILTER_FLAG_TSYNC, nullptr);
|
|
|
| -bool IsSingleThreaded(int proc_fd) {
|
| - if (proc_fd < 0) {
|
| - // Cannot determine whether program is single-threaded. Hope for
|
| - // the best...
|
| + if (rv == -1 && errno == EFAULT) {
|
| return true;
|
| - }
|
| -
|
| - struct stat sb;
|
| - int task = -1;
|
| - if ((task = openat(proc_fd, "self/task", O_RDONLY | O_DIRECTORY)) < 0 ||
|
| - fstat(task, &sb) != 0 || sb.st_nlink != 3 || IGNORE_EINTR(close(task))) {
|
| - if (task >= 0) {
|
| - if (IGNORE_EINTR(close(task))) {
|
| - }
|
| - }
|
| + } else {
|
| + // TODO(jln): turn these into DCHECK after 417888 is considered fixed.
|
| + CHECK_EQ(-1, rv);
|
| + CHECK(ENOSYS == errno || EINVAL == errno);
|
| return false;
|
| }
|
| - return true;
|
| }
|
|
|
| } // namespace
|
|
|
| -SandboxBPF::SandboxBPF()
|
| - : quiet_(false), proc_fd_(-1), sandbox_has_started_(false), policy_() {
|
| +SandboxBPF::SandboxBPF(bpf_dsl::Policy* policy)
|
| + : proc_task_fd_(), sandbox_has_started_(false), policy_(policy) {
|
| }
|
|
|
| SandboxBPF::~SandboxBPF() {
|
| }
|
|
|
| -bool SandboxBPF::IsValidSyscallNumber(int sysnum) {
|
| - return SyscallSet::IsValid(sysnum);
|
| -}
|
| -
|
| -bool SandboxBPF::RunFunctionInPolicy(void (*code_in_sandbox)(),
|
| - scoped_ptr<bpf_dsl::Policy> policy) {
|
| - // Block all signals before forking a child process. This prevents an
|
| - // attacker from manipulating our test by sending us an unexpected signal.
|
| - sigset_t old_mask, new_mask;
|
| - if (sigfillset(&new_mask) || sigprocmask(SIG_BLOCK, &new_mask, &old_mask)) {
|
| - SANDBOX_DIE("sigprocmask() failed");
|
| - }
|
| - int fds[2];
|
| - if (pipe2(fds, O_NONBLOCK | O_CLOEXEC)) {
|
| - SANDBOX_DIE("pipe() failed");
|
| - }
|
| -
|
| - if (fds[0] <= 2 || fds[1] <= 2) {
|
| - SANDBOX_DIE("Process started without standard file descriptors");
|
| - }
|
| -
|
| - // This code is using fork() and should only ever run single-threaded.
|
| - // Most of the code below is "async-signal-safe" and only minor changes
|
| - // would be needed to support threads.
|
| - DCHECK(IsSingleThreaded(proc_fd_));
|
| - pid_t pid = fork();
|
| - if (pid < 0) {
|
| - // Die if we cannot fork(). We would probably fail a little later
|
| - // anyway, as the machine is likely very close to running out of
|
| - // memory.
|
| - // But what we don't want to do is return "false", as a crafty
|
| - // attacker might cause fork() to fail at will and could trick us
|
| - // into running without a sandbox.
|
| - sigprocmask(SIG_SETMASK, &old_mask, NULL); // OK, if it fails
|
| - 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.
|
| - Die::EnableSimpleExit();
|
| -
|
| - errno = 0;
|
| - if (IGNORE_EINTR(close(fds[0]))) {
|
| - // This call to close() has been failing in strange ways. See
|
| - // crbug.com/152530. So we only fail in debug mode now.
|
| -#if !defined(NDEBUG)
|
| - WriteFailedStderrSetupMessage(fds[1]);
|
| - SANDBOX_DIE(NULL);
|
| -#endif
|
| - }
|
| - if (HANDLE_EINTR(dup2(fds[1], 2)) != 2) {
|
| - // Stderr could very well be a file descriptor to .xsession-errors, or
|
| - // another file, which could be backed by a file system that could cause
|
| - // dup2 to fail while trying to close stderr. It's important that we do
|
| - // not fail on trying to close stderr.
|
| - // If dup2 fails here, we will continue normally, this means that our
|
| - // parent won't cause a fatal failure if something writes to stderr in
|
| - // this child.
|
| -#if !defined(NDEBUG)
|
| - // In DEBUG builds, we still want to get a report.
|
| - WriteFailedStderrSetupMessage(fds[1]);
|
| - SANDBOX_DIE(NULL);
|
| -#endif
|
| - }
|
| - if (IGNORE_EINTR(close(fds[1]))) {
|
| - // This call to close() has been failing in strange ways. See
|
| - // crbug.com/152530. So we only fail in debug mode now.
|
| -#if !defined(NDEBUG)
|
| - WriteFailedStderrSetupMessage(fds[1]);
|
| - SANDBOX_DIE(NULL);
|
| -#endif
|
| - }
|
| -
|
| - SetSandboxPolicy(policy.release());
|
| - if (!StartSandbox(PROCESS_SINGLE_THREADED)) {
|
| - SANDBOX_DIE(NULL);
|
| - }
|
| -
|
| - // Run our code in the sandbox.
|
| - code_in_sandbox();
|
| -
|
| - // code_in_sandbox() is not supposed to return here.
|
| - SANDBOX_DIE(NULL);
|
| - }
|
| -
|
| - // In the parent process.
|
| - if (IGNORE_EINTR(close(fds[1]))) {
|
| - SANDBOX_DIE("close() failed");
|
| - }
|
| - if (sigprocmask(SIG_SETMASK, &old_mask, NULL)) {
|
| - SANDBOX_DIE("sigprocmask() failed");
|
| - }
|
| - int status;
|
| - if (HANDLE_EINTR(waitpid(pid, &status, 0)) != pid) {
|
| - SANDBOX_DIE("waitpid() failed unexpectedly");
|
| - }
|
| - bool rc = WIFEXITED(status) && WEXITSTATUS(status) == kExpectedExitCode;
|
| -
|
| - // 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 must 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';
|
| - SANDBOX_DIE(buf);
|
| - }
|
| - }
|
| - if (IGNORE_EINTR(close(fds[0]))) {
|
| - SANDBOX_DIE("close() failed");
|
| - }
|
| -
|
| - return rc;
|
| -}
|
| -
|
| -bool SandboxBPF::KernelSupportSeccompBPF() {
|
| - return RunFunctionInPolicy(ProbeProcess,
|
| - scoped_ptr<bpf_dsl::Policy>(new ProbePolicy())) &&
|
| - RunFunctionInPolicy(TryVsyscallProcess,
|
| - scoped_ptr<bpf_dsl::Policy>(new AllowAllPolicy()));
|
| -}
|
| -
|
| // static
|
| -SandboxBPF::SandboxStatus SandboxBPF::SupportsSeccompSandbox(int proc_fd) {
|
| - // It the sandbox is currently active, we clearly must have support for
|
| - // sandboxing.
|
| - if (status_ == STATUS_ENABLED) {
|
| - return status_;
|
| - }
|
| -
|
| - // Even if the sandbox was previously available, something might have
|
| - // changed in our run-time environment. Check one more time.
|
| - if (status_ == STATUS_AVAILABLE) {
|
| - if (!IsSingleThreaded(proc_fd)) {
|
| - status_ = STATUS_UNAVAILABLE;
|
| - }
|
| - return status_;
|
| - }
|
| -
|
| - if (status_ == STATUS_UNAVAILABLE && IsSingleThreaded(proc_fd)) {
|
| - // All state transitions resulting in STATUS_UNAVAILABLE are immediately
|
| - // preceded by STATUS_AVAILABLE. Furthermore, these transitions all
|
| - // happen, if and only if they are triggered by the process being multi-
|
| - // threaded.
|
| - // In other words, if a single-threaded process is currently in the
|
| - // STATUS_UNAVAILABLE state, it is safe to assume that sandboxing is
|
| - // actually available.
|
| - status_ = STATUS_AVAILABLE;
|
| - return status_;
|
| +bool SandboxBPF::SupportsSeccompSandbox(SeccompLevel level) {
|
| + // Never pretend to support seccomp with Valgrind, as it
|
| + // throws the tool off.
|
| + if (IsRunningOnValgrind()) {
|
| + return false;
|
| }
|
|
|
| - // If we have not previously checked for availability of the sandbox or if
|
| - // we otherwise don't believe to have a good cached value, we have to
|
| - // perform a thorough check now.
|
| - if (status_ == STATUS_UNKNOWN) {
|
| - // We create our own private copy of a "Sandbox" object. This ensures that
|
| - // the object does not have any policies configured, that might interfere
|
| - // with the tests done by "KernelSupportSeccompBPF()".
|
| - SandboxBPF sandbox;
|
| -
|
| - // By setting "quiet_ = true" we suppress messages for expected and benign
|
| - // failures (e.g. if the current kernel lacks support for BPF filters).
|
| - sandbox.quiet_ = true;
|
| - sandbox.set_proc_fd(proc_fd);
|
| - status_ = sandbox.KernelSupportSeccompBPF() ? STATUS_AVAILABLE
|
| - : STATUS_UNSUPPORTED;
|
| -
|
| - // As we are performing our tests from a child process, the run-time
|
| - // environment that is visible to the sandbox is always guaranteed to be
|
| - // single-threaded. Let's check here whether the caller is single-
|
| - // threaded. Otherwise, we mark the sandbox as temporarily unavailable.
|
| - if (status_ == STATUS_AVAILABLE && !IsSingleThreaded(proc_fd)) {
|
| - status_ = STATUS_UNAVAILABLE;
|
| - }
|
| + switch (level) {
|
| + case SeccompLevel::SINGLE_THREADED:
|
| + return KernelSupportsSeccompBPF();
|
| + case SeccompLevel::MULTI_THREADED:
|
| + return KernelSupportsSeccompTsync();
|
| }
|
| - return status_;
|
| + NOTREACHED();
|
| + return false;
|
| }
|
|
|
| -// static
|
| -SandboxBPF::SandboxStatus
|
| -SandboxBPF::SupportsSeccompThreadFilterSynchronization() {
|
| - // Applying NO_NEW_PRIVS, a BPF filter, and synchronizing the filter across
|
| - // the thread group are all handled atomically by this syscall.
|
| - const int rv = syscall(
|
| - __NR_seccomp, SECCOMP_SET_MODE_FILTER, SECCOMP_FILTER_FLAG_TSYNC, NULL);
|
| +bool SandboxBPF::StartSandbox(SeccompLevel seccomp_level) {
|
| + DCHECK(policy_);
|
| + CHECK(seccomp_level == SeccompLevel::SINGLE_THREADED ||
|
| + seccomp_level == SeccompLevel::MULTI_THREADED);
|
|
|
| - if (rv == -1 && errno == EFAULT) {
|
| - return STATUS_AVAILABLE;
|
| - } else {
|
| - // TODO(jln): turn these into DCHECK after 417888 is considered fixed.
|
| - CHECK_EQ(-1, rv);
|
| - CHECK(ENOSYS == errno || EINVAL == errno);
|
| - return STATUS_UNSUPPORTED;
|
| - }
|
| -}
|
| -
|
| -void SandboxBPF::set_proc_fd(int proc_fd) { proc_fd_ = proc_fd; }
|
| -
|
| -bool SandboxBPF::StartSandbox(SandboxThreadState thread_state) {
|
| - CHECK(thread_state == PROCESS_SINGLE_THREADED ||
|
| - thread_state == PROCESS_MULTI_THREADED);
|
| -
|
| - if (status_ == STATUS_UNSUPPORTED || status_ == STATUS_UNAVAILABLE) {
|
| - SANDBOX_DIE(
|
| - "Trying to start sandbox, even though it is known to be "
|
| - "unavailable");
|
| - return false;
|
| - } else if (sandbox_has_started_) {
|
| + if (sandbox_has_started_) {
|
| SANDBOX_DIE(
|
| "Cannot repeatedly start sandbox. Create a separate Sandbox "
|
| "object instead.");
|
| return false;
|
| }
|
| - if (proc_fd_ < 0) {
|
| - proc_fd_ = open("/proc", O_RDONLY | O_DIRECTORY);
|
| - }
|
| - if (proc_fd_ < 0) {
|
| - // For now, continue in degraded mode, if we can't access /proc.
|
| - // In the future, we might want to tighten this requirement.
|
| - }
|
|
|
| - bool supports_tsync =
|
| - SupportsSeccompThreadFilterSynchronization() == STATUS_AVAILABLE;
|
| + const bool supports_tsync = KernelSupportsSeccompTsync();
|
|
|
| - if (thread_state == PROCESS_SINGLE_THREADED) {
|
| - if (!IsSingleThreaded(proc_fd_)) {
|
| + if (seccomp_level == SeccompLevel::SINGLE_THREADED) {
|
| + if (!IsSingleThreaded(proc_task_fd_.get())) {
|
| SANDBOX_DIE("Cannot start sandbox; process is already multi-threaded");
|
| return false;
|
| }
|
| - } else if (thread_state == PROCESS_MULTI_THREADED) {
|
| - if (IsSingleThreaded(proc_fd_)) {
|
| + } else if (seccomp_level == SeccompLevel::MULTI_THREADED) {
|
| + if (IsSingleThreaded(proc_task_fd_.get())) {
|
| SANDBOX_DIE("Cannot start sandbox; "
|
| "process may be single-threaded when reported as not");
|
| return false;
|
| @@ -404,30 +139,65 @@ bool SandboxBPF::StartSandbox(SandboxThreadState thread_state) {
|
| // We no longer need access to any files in /proc. We want to do this
|
| // before installing the filters, just in case that our policy denies
|
| // close().
|
| - if (proc_fd_ >= 0) {
|
| - if (IGNORE_EINTR(close(proc_fd_))) {
|
| - SANDBOX_DIE("Failed to close file descriptor for /proc");
|
| - return false;
|
| - }
|
| - proc_fd_ = -1;
|
| + if (proc_task_fd_.is_valid()) {
|
| + proc_task_fd_.reset();
|
| }
|
|
|
| // Install the filters.
|
| - InstallFilter(supports_tsync || thread_state == PROCESS_MULTI_THREADED);
|
| -
|
| - // We are now inside the sandbox.
|
| - status_ = STATUS_ENABLED;
|
| + InstallFilter(supports_tsync ||
|
| + seccomp_level == SeccompLevel::MULTI_THREADED);
|
|
|
| return true;
|
| }
|
|
|
| -// Don't take a scoped_ptr here, polymorphism make their use awkward.
|
| -void SandboxBPF::SetSandboxPolicy(bpf_dsl::Policy* policy) {
|
| - DCHECK(!policy_);
|
| - if (sandbox_has_started_) {
|
| - SANDBOX_DIE("Cannot change policy after sandbox has started");
|
| +void SandboxBPF::SetProcTaskFd(base::ScopedFD proc_task_fd) {
|
| + proc_task_fd_.swap(proc_task_fd);
|
| +}
|
| +
|
| +// static
|
| +bool SandboxBPF::IsValidSyscallNumber(int sysnum) {
|
| + return SyscallSet::IsValid(sysnum);
|
| +}
|
| +
|
| +// static
|
| +bool SandboxBPF::IsRequiredForUnsafeTrap(int sysno) {
|
| + return bpf_dsl::PolicyCompiler::IsRequiredForUnsafeTrap(sysno);
|
| +}
|
| +
|
| +// static
|
| +intptr_t SandboxBPF::ForwardSyscall(const struct arch_seccomp_data& args) {
|
| + return Syscall::Call(
|
| + args.nr, static_cast<intptr_t>(args.args[0]),
|
| + static_cast<intptr_t>(args.args[1]), static_cast<intptr_t>(args.args[2]),
|
| + static_cast<intptr_t>(args.args[3]), static_cast<intptr_t>(args.args[4]),
|
| + static_cast<intptr_t>(args.args[5]));
|
| +}
|
| +
|
| +scoped_ptr<CodeGen::Program> SandboxBPF::AssembleFilter(
|
| + bool force_verification) {
|
| +#if !defined(NDEBUG)
|
| + force_verification = true;
|
| +#endif
|
| + DCHECK(policy_);
|
| + bpf_dsl::PolicyCompiler compiler(policy_.get(), Trap::Registry());
|
| + scoped_ptr<CodeGen::Program> program = compiler.Compile();
|
| +
|
| + // Make sure compilation resulted in a BPF program that executes
|
| + // correctly. Otherwise, there is an internal error in our BPF compiler.
|
| + // There is really nothing the caller can do until the bug is fixed.
|
| + if (force_verification) {
|
| + // Verification is expensive. We only perform this step, if we are
|
| + // compiled in debug mode, or if the caller explicitly requested
|
| + // verification.
|
| +
|
| + const char* err = NULL;
|
| + if (!Verifier::VerifyBPF(&compiler, *program, *policy_, &err)) {
|
| + bpf_dsl::DumpBPF::PrintProgram(*program);
|
| + SANDBOX_DIE(err);
|
| + }
|
| }
|
| - policy_.reset(policy);
|
| +
|
| + return program.Pass();
|
| }
|
|
|
| void SandboxBPF::InstallFilter(bool must_sync_threads) {
|
| @@ -456,69 +226,26 @@ void SandboxBPF::InstallFilter(bool must_sync_threads) {
|
| policy_.reset();
|
|
|
| if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) {
|
| - SANDBOX_DIE(quiet_ ? NULL : "Kernel refuses to enable no-new-privs");
|
| + SANDBOX_DIE("Kernel refuses to enable no-new-privs");
|
| }
|
|
|
| // Install BPF filter program. If the thread state indicates multi-threading
|
| // support, then the kernel hass the seccomp system call. Otherwise, fall
|
| // back on prctl, which requires the process to be single-threaded.
|
| if (must_sync_threads) {
|
| - int rv = syscall(__NR_seccomp, SECCOMP_SET_MODE_FILTER,
|
| - SECCOMP_FILTER_FLAG_TSYNC, reinterpret_cast<const char*>(&prog));
|
| + int rv =
|
| + sys_seccomp(SECCOMP_SET_MODE_FILTER, SECCOMP_FILTER_FLAG_TSYNC, &prog);
|
| if (rv) {
|
| - SANDBOX_DIE(quiet_ ? NULL :
|
| + SANDBOX_DIE(
|
| "Kernel refuses to turn on and synchronize threads for BPF filters");
|
| }
|
| } else {
|
| if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog)) {
|
| - SANDBOX_DIE(quiet_ ? NULL : "Kernel refuses to turn on BPF filters");
|
| + SANDBOX_DIE("Kernel refuses to turn on BPF filters");
|
| }
|
| }
|
|
|
| sandbox_has_started_ = true;
|
| }
|
|
|
| -scoped_ptr<CodeGen::Program> SandboxBPF::AssembleFilter(
|
| - bool force_verification) {
|
| -#if !defined(NDEBUG)
|
| - force_verification = true;
|
| -#endif
|
| -
|
| - bpf_dsl::PolicyCompiler compiler(policy_.get(), Trap::Registry());
|
| - scoped_ptr<CodeGen::Program> program = compiler.Compile();
|
| -
|
| - // Make sure compilation resulted in BPF program that executes
|
| - // correctly. Otherwise, there is an internal error in our BPF compiler.
|
| - // There is really nothing the caller can do until the bug is fixed.
|
| - if (force_verification) {
|
| - // Verification is expensive. We only perform this step, if we are
|
| - // compiled in debug mode, or if the caller explicitly requested
|
| - // verification.
|
| -
|
| - const char* err = NULL;
|
| - if (!Verifier::VerifyBPF(&compiler, *program, *policy_, &err)) {
|
| - bpf_dsl::DumpBPF::PrintProgram(*program);
|
| - SANDBOX_DIE(err);
|
| - }
|
| - }
|
| -
|
| - return program.Pass();
|
| -}
|
| -
|
| -bool SandboxBPF::IsRequiredForUnsafeTrap(int sysno) {
|
| - return bpf_dsl::PolicyCompiler::IsRequiredForUnsafeTrap(sysno);
|
| -}
|
| -
|
| -intptr_t SandboxBPF::ForwardSyscall(const struct arch_seccomp_data& args) {
|
| - return Syscall::Call(args.nr,
|
| - static_cast<intptr_t>(args.args[0]),
|
| - static_cast<intptr_t>(args.args[1]),
|
| - static_cast<intptr_t>(args.args[2]),
|
| - static_cast<intptr_t>(args.args[3]),
|
| - static_cast<intptr_t>(args.args[4]),
|
| - static_cast<intptr_t>(args.args[5]));
|
| -}
|
| -
|
| -SandboxBPF::SandboxStatus SandboxBPF::status_ = STATUS_UNKNOWN;
|
| -
|
| } // namespace sandbox
|
|
|