1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186
|
// Copyright 2013 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/nacl/loader/sandbox_linux/nacl_bpf_sandbox_linux.h"
#include <memory>
#include <utility>
#include "build/build_config.h"
#include "sandbox/sandbox_buildflags.h"
#if BUILDFLAG(USE_SECCOMP_BPF)
#include <errno.h>
#include <signal.h>
#include <sys/ptrace.h>
#include <sys/types.h>
#include <unistd.h>
#include "base/check_op.h"
#include "base/command_line.h"
#include "base/compiler_specific.h"
#include "base/files/scoped_file.h"
#include "base/functional/callback.h"
#include "base/notreached.h"
#include "components/nacl/common/nacl_switches.h"
#include "sandbox/linux/bpf_dsl/bpf_dsl.h"
#include "sandbox/linux/bpf_dsl/policy.h"
#include "sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.h"
#include "sandbox/linux/system_headers/linux_syscalls.h"
#include "sandbox/policy/linux/sandbox_seccomp_bpf_linux.h"
#endif // BUILDFLAG(USE_SECCOMP_BPF)
namespace nacl {
#if BUILDFLAG(USE_SECCOMP_BPF)
namespace {
using sandbox::bpf_dsl::Allow;
using sandbox::bpf_dsl::Error;
using sandbox::bpf_dsl::ResultExpr;
class NaClBPFSandboxPolicy : public sandbox::bpf_dsl::Policy {
public:
NaClBPFSandboxPolicy()
: baseline_policy_(
sandbox::policy::SandboxSeccompBPF::GetBaselinePolicy()),
policy_pid_(syscall(__NR_getpid)) {
const base::CommandLine* command_line =
base::CommandLine::ForCurrentProcess();
// nacl_process_host.cc doesn't always enable the debug stub when
// kEnableNaClDebug is passed, but it's OK to enable the extra syscalls
// whenever kEnableNaClDebug is passed.
enable_nacl_debug_ = command_line->HasSwitch(switches::kEnableNaClDebug);
}
NaClBPFSandboxPolicy(const NaClBPFSandboxPolicy&) = delete;
NaClBPFSandboxPolicy& operator=(const NaClBPFSandboxPolicy&) = delete;
~NaClBPFSandboxPolicy() override = default;
ResultExpr EvaluateSyscall(int system_call_number) const override;
ResultExpr InvalidSyscall() const override {
return baseline_policy_->InvalidSyscall();
}
private:
std::unique_ptr<sandbox::bpf_dsl::Policy> baseline_policy_;
bool enable_nacl_debug_;
const pid_t policy_pid_;
};
ResultExpr NaClBPFSandboxPolicy::EvaluateSyscall(int sysno) const {
DCHECK(baseline_policy_);
// EvaluateSyscall must be called from the same process that instantiated the
// NaClBPFSandboxPolicy.
DCHECK_EQ(policy_pid_, syscall(__NR_getpid));
// NaCl's GDB debug stub uses the following socket system calls. We only
// allow them when --enable-nacl-debug is specified.
if (enable_nacl_debug_) {
switch (sysno) {
// trusted/service_runtime/linux/thread_suspension.c needs sigwait(). Thread
// suspension is currently only used in the debug stub.
case __NR_rt_sigtimedwait:
return Allow();
#if defined(__x86_64__) || defined(__arm__) || defined(__mips__)
// transport_common.cc needs this.
case __NR_accept:
case __NR_setsockopt:
return Allow();
#elif defined(__i386__)
case __NR_socketcall:
return Allow();
#endif
default:
break;
}
}
switch (sysno) {
#if defined(__i386__) || defined(__mips__)
// Needed on i386 to set-up the custom segments.
case __NR_modify_ldt:
#endif
// NaCl uses custom signal stacks.
case __NR_sigaltstack:
// Below is fairly similar to the policy for a Chromium renderer.
#if defined(__i386__) || defined(__x86_64__) || defined(__mips__) || \
defined(__aarch64__)
case __NR_getrlimit:
#endif
#if defined(__i386__) || defined(__arm__)
case __NR_ugetrlimit:
#endif
// NaCl runtime uses flock to simulate POSIX behavior for pwrite.
case __NR_flock:
case __NR_pwrite64:
// set_robust_list(2) is generating quite a bit of logspam on Chrome OS
// (and probably on Linux too), and per its manpage it should never EPERM.
// Moreover, it also doesn't allow affecting other processes, since it
// doesn't take a |pid| argument.
// See crbug.com/1051197 for details.
case __NR_set_robust_list:
case __NR_sched_get_priority_max:
case __NR_sched_get_priority_min:
case __NR_sysinfo:
// __NR_times needed as clock() is called by CommandBufferHelper, which is
// used by NaCl applications that use Pepper's 3D interfaces.
// See crbug.com/264856 for details.
case __NR_times:
case __NR_uname:
return Allow();
case __NR_ioctl:
case __NR_ptrace:
return Error(EPERM);
case __NR_sched_getaffinity:
case __NR_sched_getparam:
case __NR_sched_getscheduler:
case __NR_sched_setscheduler:
return sandbox::RestrictSchedTarget(policy_pid_, sysno);
// NaClAddrSpaceBeforeAlloc needs prlimit64.
case __NR_prlimit64:
return sandbox::RestrictPrlimit64(policy_pid_);
// NaCl runtime exposes clock_getres to untrusted code.
case __NR_clock_getres:
return sandbox::RestrictClockID();
default:
return baseline_policy_->EvaluateSyscall(sysno);
}
NOTREACHED();
}
void RunSandboxSanityChecks() {
errno = 0;
// Make a ptrace request with an invalid PID.
long ptrace_ret = ptrace(PTRACE_PEEKUSER, -1 /* pid */, NULL, NULL);
CHECK_EQ(-1, ptrace_ret);
// Without the sandbox on, this ptrace call would ESRCH instead.
CHECK_EQ(EPERM, errno);
}
} // namespace
#else
#error "Seccomp-bpf disabled on supported architecture!"
#endif // BUILDFLAG(USE_SECCOMP_BPF)
bool InitializeBPFSandbox(base::ScopedFD proc_fd) {
#if BUILDFLAG(USE_SECCOMP_BPF)
if (sandbox::policy::SandboxSeccompBPF::StartSandboxWithExternalPolicy(
std::make_unique<NaClBPFSandboxPolicy>(), std::move(proc_fd))) {
RunSandboxSanityChecks();
return true;
}
#endif // BUILDFLAG(USE_SECCOMP_BPF)
return false;
}
} // namespace nacl
|