15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Some headers on Android are missing cdefs: crbug.com/172337.
62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// (We can't use OS_ANDROID here since build_config.h is not included).
72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#if defined(ANDROID)
82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <sys/cdefs.h>
92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#endif
102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <errno.h>
122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <fcntl.h>
132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <string.h>
142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <sys/prctl.h>
152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <sys/stat.h>
162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <sys/syscall.h>
172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <sys/types.h>
182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <time.h>
192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <unistd.h>
202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#ifndef SECCOMP_BPF_STANDALONE
222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/logging.h"
232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/posix/eintr_wrapper.h"
242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#endif
252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sandbox/linux/seccomp-bpf/codegen.h"
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sandbox/linux/seccomp-bpf/sandbox_bpf.h"
282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "sandbox/linux/seccomp-bpf/syscall.h"
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sandbox/linux/seccomp-bpf/syscall_iterator.h"
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sandbox/linux/seccomp-bpf/verifier.h"
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)using playground2::ErrorCode;
352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)using playground2::Instruction;
362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)using playground2::Sandbox;
372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)using playground2::Trap;
382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)using playground2::arch_seccomp_data;
392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const int kExpectedExitCode = 100;
412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)template<class T> int popcount(T x);
432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)template<> int popcount<unsigned int>(unsigned int x) {
442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return __builtin_popcount(x);
452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)template<> int popcount<unsigned long>(unsigned long x) {
472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return __builtin_popcountl(x);
482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)template<> int popcount<unsigned long long>(unsigned long long x) {
502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return __builtin_popcountll(x);
512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WriteFailedStderrSetupMessage(int out_fd) {
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const char* error_string = strerror(errno);
552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  static const char msg[] = "You have reproduced a puzzling issue.\n"
562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                            "Please, report to crbug.com/152530!\n"
572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                            "Failed to set up stderr: ";
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (HANDLE_EINTR(write(out_fd, msg, sizeof(msg)-1)) > 0 && error_string &&
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      HANDLE_EINTR(write(out_fd, error_string, strlen(error_string))) > 0 &&
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      HANDLE_EINTR(write(out_fd, "\n", 1))) {
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// We define a really simple sandbox policy. It is just good enough for us
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// to tell that the sandbox has actually been activated.
662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)ErrorCode ProbeEvaluator(Sandbox *, int sysnum, void *) __attribute__((const));
672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)ErrorCode ProbeEvaluator(Sandbox *, int sysnum, void *) {
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (sysnum) {
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  case __NR_getpid:
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Return EPERM so that we can check that the filter actually ran.
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return ErrorCode(EPERM);
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  case __NR_exit_group:
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Allow exit() with a non-default return code.
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return ErrorCode(ErrorCode::ERR_ALLOWED);
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  default:
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Make everything else fail in an easily recognizable way.
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return ErrorCode(EINVAL);
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ProbeProcess(void) {
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (syscall(__NR_getpid) < 0 && errno == EPERM) {
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    syscall(__NR_exit_group, static_cast<intptr_t>(kExpectedExitCode));
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)ErrorCode AllowAllEvaluator(Sandbox *, int sysnum, void *) {
882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!Sandbox::IsValidSyscallNumber(sysnum)) {
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return ErrorCode(ENOSYS);
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return ErrorCode(ErrorCode::ERR_ALLOWED);
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void TryVsyscallProcess(void) {
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  time_t current_time;
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // time() is implemented as a vsyscall. With an older glibc, with
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // vsyscall=emulate and some versions of the seccomp BPF patch
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // we may get SIGKILL-ed. Detect this!
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (time(&current_time) != static_cast<time_t>(-1)) {
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    syscall(__NR_exit_group, static_cast<intptr_t>(kExpectedExitCode));
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool IsSingleThreaded(int proc_fd) {
1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (proc_fd < 0) {
1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Cannot determine whether program is single-threaded. Hope for
1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // the best...
1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return true;
1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  struct stat sb;
1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int task = -1;
1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if ((task = openat(proc_fd, "self/task", O_RDONLY|O_DIRECTORY)) < 0 ||
1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      fstat(task, &sb) != 0 ||
1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      sb.st_nlink != 3 ||
1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      HANDLE_EINTR(close(task))) {
1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (task >= 0) {
1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (HANDLE_EINTR(close(task))) { }
1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
1212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return true;
1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool IsDenied(const ErrorCode& code) {
1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return (code.err() & SECCOMP_RET_ACTION) == SECCOMP_RET_TRAP ||
1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)         (code.err() >= (SECCOMP_RET_ERRNO + ErrorCode::ERR_MIN_ERRNO) &&
1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          code.err() <= (SECCOMP_RET_ERRNO + ErrorCode::ERR_MAX_ERRNO));
1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Function that can be passed as a callback function to CodeGen::Traverse().
1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Checks whether the "insn" returns an UnsafeTrap() ErrorCode. If so, it
1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// sets the "bool" variable pointed to by "aux".
1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void CheckForUnsafeErrorCodes(Instruction *insn, void *aux) {
1352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool *is_unsafe = static_cast<bool *>(aux);
1362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!*is_unsafe) {
1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (BPF_CLASS(insn->code) == BPF_RET &&
1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        insn->k > SECCOMP_RET_TRAP &&
1392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        insn->k - SECCOMP_RET_TRAP <= SECCOMP_RET_DATA) {
1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      const ErrorCode& err =
1412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        Trap::ErrorCodeFromTrapId(insn->k & SECCOMP_RET_DATA);
1422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (err.error_type() != ErrorCode::ET_INVALID && !err.safe()) {
1432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        *is_unsafe = true;
1442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      }
1452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
1462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// A Trap() handler that returns an "errno" value. The value is encoded
1502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// in the "aux" parameter.
1512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)intptr_t ReturnErrno(const struct arch_seccomp_data&, void *aux) {
1522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // TrapFnc functions report error by following the native kernel convention
1532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // of returning an exit code in the range of -1..-4096. They do not try to
1542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // set errno themselves. The glibc wrapper that triggered the SIGSYS will
1552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // ultimately do so for us.
1562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int err = reinterpret_cast<intptr_t>(aux) & SECCOMP_RET_DATA;
1572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return -err;
1582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Function that can be passed as a callback function to CodeGen::Traverse().
1612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Checks whether the "insn" returns an errno value from a BPF filter. If so,
1622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// it rewrites the instruction to instead call a Trap() handler that does
1632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// the same thing. "aux" is ignored.
1642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void RedirectToUserspace(Instruction *insn, void *aux) {
1652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // When inside an UnsafeTrap() callback, we want to allow all system calls.
1662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // This means, we must conditionally disable the sandbox -- and that's not
1672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // something that kernel-side BPF filters can do, as they cannot inspect
1682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // any state other than the syscall arguments.
1692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // But if we redirect all error handlers to user-space, then we can easily
1702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // make this decision.
1712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // The performance penalty for this extra round-trip to user-space is not
1722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // actually that bad, as we only ever pay it for denied system calls; and a
1732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // typical program has very few of these.
1742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Sandbox *sandbox = static_cast<Sandbox *>(aux);
1752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (BPF_CLASS(insn->code) == BPF_RET &&
1762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      (insn->k & SECCOMP_RET_ACTION) == SECCOMP_RET_ERRNO) {
1772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    insn->k = sandbox->Trap(ReturnErrno,
1782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   reinterpret_cast<void *>(insn->k & SECCOMP_RET_DATA)).err();
1792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Stackable wrapper around an Evaluators handler. Changes ErrorCodes
1832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// returned by a system call evaluator to match the changes made by
1842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// RedirectToUserspace(). "aux" should be pointer to wrapped system call
1852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// evaluator.
1862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)ErrorCode RedirectToUserspaceEvalWrapper(Sandbox *sandbox, int sysnum,
1872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                         void *aux) {
1882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // We need to replicate the behavior of RedirectToUserspace(), so that our
1892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Verifier can still work correctly.
1902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Sandbox::Evaluators *evaluators =
1912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    reinterpret_cast<Sandbox::Evaluators *>(aux);
1922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const std::pair<Sandbox::EvaluateSyscall, void *>& evaluator =
1932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    *evaluators->begin();
1942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ErrorCode err = evaluator.first(sandbox, sysnum, evaluator.second);
1962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if ((err.err() & SECCOMP_RET_ACTION) == SECCOMP_RET_ERRNO) {
1972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return sandbox->Trap(ReturnErrno,
1982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                       reinterpret_cast<void *>(err.err() & SECCOMP_RET_DATA));
1992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return err;
2012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)intptr_t BpfFailure(const struct arch_seccomp_data&, void *aux) {
2042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  SANDBOX_DIE(static_cast<char *>(aux));
2052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace
2082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// The kernel gives us a sandbox, we turn it into a playground :-)
2102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// This is version 2 of the playground; version 1 was built on top of
2112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// pre-BPF seccomp mode.
2122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace playground2 {
2132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)Sandbox::Sandbox()
2152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    : quiet_(false),
2162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      proc_fd_(-1),
2172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      evaluators_(new Evaluators),
2182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      conds_(new Conds) {
2192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)Sandbox::~Sandbox() {
2222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // It is generally unsafe to call any memory allocator operations or to even
2232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // call arbitrary destructors after having installed a new policy. We just
2242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // have no way to tell whether this policy would allow the system calls that
2252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // the constructors can trigger.
2262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // So, we normally destroy all of our complex state prior to starting the
2272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // sandbox. But this won't happen, if the Sandbox object was created and
2282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // never actually used to set up a sandbox. So, just in case, we are
2292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // destroying any remaining state.
2302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // The "if ()" statements are technically superfluous. But let's be explicit
2312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // that we really don't want to run any code, when we already destroyed
2322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // objects before setting up the sandbox.
2332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (evaluators_) {
2342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    delete evaluators_;
2352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (conds_) {
2372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    delete conds_;
2382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool Sandbox::IsValidSyscallNumber(int sysnum) {
2422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return SyscallIterator::IsValid(sysnum);
2432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool Sandbox::RunFunctionInPolicy(void (*code_in_sandbox)(),
2472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                  Sandbox::EvaluateSyscall syscall_evaluator,
2482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                  void *aux) {
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Block all signals before forking a child process. This prevents an
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // attacker from manipulating our test by sending us an unexpected signal.
2512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  sigset_t old_mask, new_mask;
2522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (sigfillset(&new_mask) ||
2532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      sigprocmask(SIG_BLOCK, &new_mask, &old_mask)) {
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SANDBOX_DIE("sigprocmask() failed");
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int fds[2];
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (pipe2(fds, O_NONBLOCK|O_CLOEXEC)) {
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SANDBOX_DIE("pipe() failed");
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (fds[0] <= 2 || fds[1] <= 2) {
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SANDBOX_DIE("Process started without standard file descriptors");
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pid_t pid = fork();
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (pid < 0) {
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Die if we cannot fork(). We would probably fail a little later
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // anyway, as the machine is likely very close to running out of
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // memory.
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // But what we don't want to do is return "false", as a crafty
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // attacker might cause fork() to fail at will and could trick us
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // into running without a sandbox.
2732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    sigprocmask(SIG_SETMASK, &old_mask, NULL);  // OK, if it fails
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SANDBOX_DIE("fork() failed unexpectedly");
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // In the child process
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!pid) {
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Test a very simple sandbox policy to verify that we can
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // successfully turn on sandboxing.
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Die::EnableSimpleExit();
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    errno = 0;
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (HANDLE_EINTR(close(fds[0]))) {
2852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // This call to close() has been failing in strange ways. See
2862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // crbug.com/152530. So we only fail in debug mode now.
2872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#if !defined(NDEBUG)
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      WriteFailedStderrSetupMessage(fds[1]);
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      SANDBOX_DIE(NULL);
2902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#endif
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (HANDLE_EINTR(dup2(fds[1], 2)) != 2) {
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Stderr could very well be a file descriptor to .xsession-errors, or
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // another file, which could be backed by a file system that could cause
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // dup2 to fail while trying to close stderr. It's important that we do
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // not fail on trying to close stderr.
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // If dup2 fails here, we will continue normally, this means that our
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // parent won't cause a fatal failure if something writes to stderr in
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // this child.
3002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#if !defined(NDEBUG)
3012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // In DEBUG builds, we still want to get a report.
3022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      WriteFailedStderrSetupMessage(fds[1]);
3032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      SANDBOX_DIE(NULL);
3042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#endif
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (HANDLE_EINTR(close(fds[1]))) {
3072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // This call to close() has been failing in strange ways. See
3082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // crbug.com/152530. So we only fail in debug mode now.
3092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#if !defined(NDEBUG)
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      WriteFailedStderrSetupMessage(fds[1]);
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      SANDBOX_DIE(NULL);
3122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#endif
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    SetSandboxPolicy(syscall_evaluator, aux);
3162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    StartSandbox();
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Run our code in the sandbox.
3192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    code_in_sandbox();
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // code_in_sandbox() is not supposed to return here.
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SANDBOX_DIE(NULL);
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // In the parent process.
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (HANDLE_EINTR(close(fds[1]))) {
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SANDBOX_DIE("close() failed");
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (sigprocmask(SIG_SETMASK, &old_mask, NULL)) {
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SANDBOX_DIE("sigprocmask() failed");
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int status;
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (HANDLE_EINTR(waitpid(pid, &status, 0)) != pid) {
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SANDBOX_DIE("waitpid() failed unexpectedly");
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool rc = WIFEXITED(status) && WEXITSTATUS(status) == kExpectedExitCode;
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If we fail to support sandboxing, there might be an additional
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // error message. If so, this was an entirely unexpected and fatal
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // failure. We should report the failure and somebody must fix
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // things. This is probably a security-critical bug in the sandboxing
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // code.
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!rc) {
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    char buf[4096];
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ssize_t len = HANDLE_EINTR(read(fds[0], buf, sizeof(buf) - 1));
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (len > 0) {
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      while (len > 1 && buf[len-1] == '\n') {
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        --len;
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      buf[len] = '\000';
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      SANDBOX_DIE(buf);
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (HANDLE_EINTR(close(fds[0]))) {
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SANDBOX_DIE("close() failed");
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return rc;
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool Sandbox::KernelSupportSeccompBPF() {
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return
3632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    RunFunctionInPolicy(ProbeProcess, ProbeEvaluator, 0) &&
3642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    RunFunctionInPolicy(TryVsyscallProcess, AllowAllEvaluator, 0);
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)Sandbox::SandboxStatus Sandbox::SupportsSeccompSandbox(int proc_fd) {
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // It the sandbox is currently active, we clearly must have support for
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // sandboxing.
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (status_ == STATUS_ENABLED) {
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return status_;
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Even if the sandbox was previously available, something might have
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // changed in our run-time environment. Check one more time.
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (status_ == STATUS_AVAILABLE) {
3772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (!IsSingleThreaded(proc_fd)) {
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      status_ = STATUS_UNAVAILABLE;
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return status_;
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (status_ == STATUS_UNAVAILABLE && IsSingleThreaded(proc_fd)) {
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // All state transitions resulting in STATUS_UNAVAILABLE are immediately
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // preceded by STATUS_AVAILABLE. Furthermore, these transitions all
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // happen, if and only if they are triggered by the process being multi-
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // threaded.
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // In other words, if a single-threaded process is currently in the
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // STATUS_UNAVAILABLE state, it is safe to assume that sandboxing is
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // actually available.
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    status_ = STATUS_AVAILABLE;
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return status_;
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If we have not previously checked for availability of the sandbox or if
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // we otherwise don't believe to have a good cached value, we have to
3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // perform a thorough check now.
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (status_ == STATUS_UNKNOWN) {
3992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // We create our own private copy of a "Sandbox" object. This ensures that
4002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // the object does not have any policies configured, that might interfere
4012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // with the tests done by "KernelSupportSeccompBPF()".
4022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    Sandbox sandbox;
4032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // By setting "quiet_ = true" we suppress messages for expected and benign
4052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // failures (e.g. if the current kernel lacks support for BPF filters).
4062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    sandbox.quiet_ = true;
4072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    sandbox.set_proc_fd(proc_fd);
4082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    status_ = sandbox.KernelSupportSeccompBPF()
4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ? STATUS_AVAILABLE : STATUS_UNSUPPORTED;
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // As we are performing our tests from a child process, the run-time
4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // environment that is visible to the sandbox is always guaranteed to be
4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // single-threaded. Let's check here whether the caller is single-
4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // threaded. Otherwise, we mark the sandbox as temporarily unavailable.
4152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (status_ == STATUS_AVAILABLE && !IsSingleThreaded(proc_fd)) {
4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      status_ = STATUS_UNAVAILABLE;
4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return status_;
4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void Sandbox::set_proc_fd(int proc_fd) {
4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  proc_fd_ = proc_fd;
4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void Sandbox::StartSandbox() {
4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (status_ == STATUS_UNSUPPORTED || status_ == STATUS_UNAVAILABLE) {
4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SANDBOX_DIE("Trying to start sandbox, even though it is known to be "
4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                "unavailable");
4302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  } else if (!evaluators_ || !conds_) {
4312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    SANDBOX_DIE("Cannot repeatedly start sandbox. Create a separate Sandbox "
4322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                "object instead.");
4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (proc_fd_ < 0) {
4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    proc_fd_ = open("/proc", O_RDONLY|O_DIRECTORY);
4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (proc_fd_ < 0) {
4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // For now, continue in degraded mode, if we can't access /proc.
4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // In the future, we might want to tighten this requirement.
4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!IsSingleThreaded(proc_fd_)) {
4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SANDBOX_DIE("Cannot start sandbox, if process is already multi-threaded");
4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We no longer need access to any files in /proc. We want to do this
4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // before installing the filters, just in case that our policy denies
4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // close().
4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (proc_fd_ >= 0) {
4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (HANDLE_EINTR(close(proc_fd_))) {
4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      SANDBOX_DIE("Failed to close file descriptor for /proc");
4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    proc_fd_ = -1;
4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Install the filters.
4562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  InstallFilter();
4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We are now inside the sandbox.
4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  status_ = STATUS_ENABLED;
4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void Sandbox::PolicySanityChecks(EvaluateSyscall syscall_evaluator,
4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                 void *aux) {
4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (SyscallIterator iter(true); !iter.Done(); ) {
4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    uint32_t sysnum = iter.Next();
4662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (!IsDenied(syscall_evaluator(this, sysnum, aux))) {
4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      SANDBOX_DIE("Policies should deny system calls that are outside the "
4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  "expected range (typically MIN_SYSCALL..MAX_SYSCALL)");
4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return;
4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void Sandbox::SetSandboxPolicy(EvaluateSyscall syscall_evaluator, void *aux) {
4752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!evaluators_ || !conds_) {
4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SANDBOX_DIE("Cannot change policy after sandbox has started");
4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  PolicySanityChecks(syscall_evaluator, aux);
4792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  evaluators_->push_back(std::make_pair(syscall_evaluator, aux));
4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void Sandbox::InstallFilter() {
4832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // We want to be very careful in not imposing any requirements on the
4842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // policies that are set with SetSandboxPolicy(). This means, as soon as
4852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // the sandbox is active, we shouldn't be relying on libraries that could
4862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // be making system calls. This, for example, means we should avoid
4872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // using the heap and we should avoid using STL functions.
4882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Temporarily copy the contents of the "program" vector into a
4892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // stack-allocated array; and then explicitly destroy that object.
4902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // This makes sure we don't ex- or implicitly call new/delete after we
4912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // installed the BPF filter program in the kernel. Depending on the
4922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // system memory allocator that is in effect, these operators can result
4932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // in system calls to things like munmap() or brk().
4942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Program *program = AssembleFilter(false /* force_verification */);
4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  struct sock_filter bpf[program->size()];
4972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const struct sock_fprog prog = {
4982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    static_cast<unsigned short>(program->size()), bpf };
4992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  memcpy(bpf, &(*program)[0], sizeof(bpf));
5002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  delete program;
5012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Release memory that is no longer needed
5032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  delete evaluators_;
5042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  delete conds_;
5052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  evaluators_ = NULL;
5062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  conds_      = NULL;
5072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Install BPF filter program
5092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) {
5102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    SANDBOX_DIE(quiet_ ? NULL : "Kernel refuses to enable no-new-privs");
5112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  } else {
5122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog)) {
5132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      SANDBOX_DIE(quiet_ ? NULL : "Kernel refuses to turn on BPF filters");
5142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return;
5182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
5192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)Sandbox::Program *Sandbox::AssembleFilter(bool force_verification) {
5212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#if !defined(NDEBUG)
5222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  force_verification = true;
5232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#endif
5242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Verify that the user pushed a policy.
5262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (evaluators_->empty()) {
5272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    SANDBOX_DIE("Failed to configure system call filters");
5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We can't handle stacked evaluators, yet. We'll get there eventually
5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // though. Hang tight.
5322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (evaluators_->size() != 1) {
5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SANDBOX_DIE("Not implemented");
5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Assemble the BPF filter program.
5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CodeGen *gen = new CodeGen();
5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!gen) {
5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SANDBOX_DIE("Out of memory");
5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If the architecture doesn't match SECCOMP_ARCH, disallow the
5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // system call.
5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Instruction *tail;
5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Instruction *head =
5462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    gen->MakeInstruction(BPF_LD+BPF_W+BPF_ABS, SECCOMP_ARCH_IDX,
5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  tail =
5482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    gen->MakeInstruction(BPF_JMP+BPF_JEQ+BPF_K, SECCOMP_ARCH,
5492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                         NULL,
5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    gen->MakeInstruction(BPF_RET+BPF_K,
5512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                         Kill("Invalid audit architecture in BPF filter"))));
5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool has_unsafe_traps = false;
5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  {
5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Evaluate all possible system calls and group their ErrorCodes into
5565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // ranges of identical codes.
5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Ranges ranges;
5582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    FindRanges(&ranges);
5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Compile the system call ranges to an optimized BPF jumptable
5615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Instruction *jumptable =
5622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      AssembleJumpTable(gen, ranges.begin(), ranges.end());
5632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // If there is at least one UnsafeTrap() in our program, the entire sandbox
5652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // is unsafe. We need to modify the program so that all non-
5662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // SECCOMP_RET_ALLOW ErrorCodes are handled in user-space. This will then
5672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // allow us to temporarily disable sandboxing rules inside of callbacks to
5682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // UnsafeTrap().
5692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    gen->Traverse(jumptable, CheckForUnsafeErrorCodes, &has_unsafe_traps);
5702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Grab the system call number, so that we can implement jump tables.
5722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    Instruction *load_nr =
5732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      gen->MakeInstruction(BPF_LD+BPF_W+BPF_ABS, SECCOMP_NR_IDX);
5742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // If our BPF program has unsafe jumps, enable support for them. This
5762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // test happens very early in the BPF filter program. Even before we
5772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // consider looking at system call numbers.
5782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // As support for unsafe jumps essentially defeats all the security
5792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // measures that the sandbox provides, we print a big warning message --
5802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // and of course, we make sure to only ever enable this feature if it
5812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // is actually requested by the sandbox policy.
5822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (has_unsafe_traps) {
5832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (SandboxSyscall(-1) == -1 && errno == ENOSYS) {
5842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        SANDBOX_DIE("Support for UnsafeTrap() has not yet been ported to this "
5852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                    "architecture");
5862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      }
5872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      EvaluateSyscall evaluateSyscall = evaluators_->begin()->first;
5892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      void *aux                       = evaluators_->begin()->second;
5902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (!evaluateSyscall(this, __NR_rt_sigprocmask, aux).
5912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            Equals(ErrorCode(ErrorCode::ERR_ALLOWED)) ||
5922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          !evaluateSyscall(this, __NR_rt_sigreturn, aux).
5932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            Equals(ErrorCode(ErrorCode::ERR_ALLOWED))
5942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#if defined(__NR_sigprocmask)
5952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)       || !evaluateSyscall(this, __NR_sigprocmask, aux).
5962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            Equals(ErrorCode(ErrorCode::ERR_ALLOWED))
5972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#endif
5982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#if defined(__NR_sigreturn)
5992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)       || !evaluateSyscall(this, __NR_sigreturn, aux).
6002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            Equals(ErrorCode(ErrorCode::ERR_ALLOWED))
6012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#endif
6022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          ) {
6032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        SANDBOX_DIE("Invalid seccomp policy; if using UnsafeTrap(), you must "
6042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                    "unconditionally allow sigreturn() and sigprocmask()");
6052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      }
6062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (!Trap::EnableUnsafeTrapsInSigSysHandler()) {
6082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        // We should never be able to get here, as UnsafeTrap() should never
6092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        // actually return a valid ErrorCode object unless the user set the
6102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        // CHROME_SANDBOX_DEBUGGING environment variable; and therefore,
6112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        // "has_unsafe_traps" would always be false. But better double-check
6122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        // than enabling dangerous code.
6132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        SANDBOX_DIE("We'd rather die than enable unsafe traps");
6142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      }
6152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      gen->Traverse(jumptable, RedirectToUserspace, this);
6162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // Allow system calls, if they originate from our magic return address
6182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // (which we can query by calling SandboxSyscall(-1)).
6192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      uintptr_t syscall_entry_point =
6202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        static_cast<uintptr_t>(SandboxSyscall(-1));
6212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      uint32_t low = static_cast<uint32_t>(syscall_entry_point);
6222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#if __SIZEOF_POINTER__ > 4
6232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      uint32_t hi  = static_cast<uint32_t>(syscall_entry_point >> 32);
6242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#endif
6252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // BPF cannot do native 64bit comparisons. On 64bit architectures, we
6272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // have to compare both 32bit halves of the instruction pointer. If they
6282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // match what we expect, we return ERR_ALLOWED. If either or both don't
6292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // match, we continue evalutating the rest of the sandbox policy.
6302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      Instruction *escape_hatch =
6312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        gen->MakeInstruction(BPF_LD+BPF_W+BPF_ABS, SECCOMP_IP_LSB_IDX,
6322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        gen->MakeInstruction(BPF_JMP+BPF_JEQ+BPF_K, low,
6332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#if __SIZEOF_POINTER__ > 4
6342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        gen->MakeInstruction(BPF_LD+BPF_W+BPF_ABS, SECCOMP_IP_MSB_IDX,
6352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        gen->MakeInstruction(BPF_JMP+BPF_JEQ+BPF_K, hi,
6362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#endif
6372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        gen->MakeInstruction(BPF_RET+BPF_K, ErrorCode(ErrorCode::ERR_ALLOWED)),
6382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#if __SIZEOF_POINTER__ > 4
6392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                             load_nr)),
6402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#endif
6412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                             load_nr));
6422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      gen->JoinInstructions(tail, escape_hatch);
6432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    } else {
6442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      gen->JoinInstructions(tail, load_nr);
6452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
6462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    tail = load_nr;
6472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // On Intel architectures, verify that system call numbers are in the
6492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // expected number range. The older i386 and x86-64 APIs clear bit 30
6502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // on all system calls. The newer x32 API always sets bit 30.
6512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#if defined(__i386__) || defined(__x86_64__)
6522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    Instruction *invalidX32 =
6532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      gen->MakeInstruction(BPF_RET+BPF_K,
6542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                           Kill("Illegal mixing of system call ABIs").err_);
6552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    Instruction *checkX32 =
6562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#if defined(__x86_64__) && defined(__ILP32__)
6572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      gen->MakeInstruction(BPF_JMP+BPF_JSET+BPF_K, 0x40000000, 0, invalidX32);
6582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#else
6592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      gen->MakeInstruction(BPF_JMP+BPF_JSET+BPF_K, 0x40000000, invalidX32, 0);
6602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#endif
6612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      gen->JoinInstructions(tail, checkX32);
6622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      tail = checkX32;
6632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#endif
6645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Append jump table to our pre-amble
6665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    gen->JoinInstructions(tail, jumptable);
6675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Turn the DAG into a vector of instructions.
6705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Program *program = new Program();
6715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gen->Compile(head, program);
6725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  delete gen;
6735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Make sure compilation resulted in BPF program that executes
6755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // correctly. Otherwise, there is an internal error in our BPF compiler.
6765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // There is really nothing the caller can do until the bug is fixed.
6772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (force_verification) {
6782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Verification is expensive. We only perform this step, if we are
6792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // compiled in debug mode, or if the caller explicitly requested
6802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // verification.
6812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    VerifyProgram(*program, has_unsafe_traps);
6825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return program;
6852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
6865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void Sandbox::VerifyProgram(const Program& program, bool has_unsafe_traps) {
6882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // If we previously rewrote the BPF program so that it calls user-space
6892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // whenever we return an "errno" value from the filter, then we have to
6902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // wrap our system call evaluator to perform the same operation. Otherwise,
6912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // the verifier would also report a mismatch in return codes.
6922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Evaluators redirected_evaluators;
6932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  redirected_evaluators.push_back(
6942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      std::make_pair(RedirectToUserspaceEvalWrapper, evaluators_));
6955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const char *err = NULL;
6972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!Verifier::VerifyBPF(
6982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                       this,
6992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                       program,
7002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                       has_unsafe_traps ? redirected_evaluators : *evaluators_,
7012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                       &err)) {
7022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    CodeGen::PrintProgram(program);
7032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    SANDBOX_DIE(err);
7042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
7055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void Sandbox::FindRanges(Ranges *ranges) {
7085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Please note that "struct seccomp_data" defines system calls as a signed
7095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // int32_t, but BPF instructions always operate on unsigned quantities. We
7105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // deal with this disparity by enumerating from MIN_SYSCALL to MAX_SYSCALL,
7115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // and then verifying that the rest of the number range (both positive and
7125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // negative) all return the same ErrorCode.
7132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  EvaluateSyscall evaluate_syscall = evaluators_->begin()->first;
7142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  void *aux                        = evaluators_->begin()->second;
7152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  uint32_t old_sysnum              = 0;
7162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ErrorCode old_err                = evaluate_syscall(this, old_sysnum, aux);
7172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ErrorCode invalid_err            = evaluate_syscall(this, MIN_SYSCALL - 1,
7182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                                      aux);
7195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (SyscallIterator iter(false); !iter.Done(); ) {
7205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    uint32_t sysnum = iter.Next();
7212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ErrorCode err = evaluate_syscall(this, static_cast<int>(sysnum), aux);
7222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (!iter.IsValid(sysnum) && !invalid_err.Equals(err)) {
7235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // A proper sandbox policy should always treat system calls outside of
7245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // the range MIN_SYSCALL..MAX_SYSCALL (i.e. anything that returns
7255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // "false" for SyscallIterator::IsValid()) identically. Typically, all
7265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // of these system calls would be denied with the same ErrorCode.
7275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      SANDBOX_DIE("Invalid seccomp policy");
7285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
7292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (!err.Equals(old_err) || iter.Done()) {
7302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      ranges->push_back(Range(old_sysnum, sysnum - 1, old_err));
7312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      old_sysnum = sysnum;
7322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      old_err    = err;
7335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
7345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)Instruction *Sandbox::AssembleJumpTable(CodeGen *gen,
7385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                        Ranges::const_iterator start,
7395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                        Ranges::const_iterator stop) {
7405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We convert the list of system call ranges into jump table that performs
7415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // a binary search over the ranges.
7425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // As a sanity check, we need to have at least one distinct ranges for us
7435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // to be able to build a jump table.
7445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (stop - start <= 0) {
7455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SANDBOX_DIE("Invalid set of system call ranges");
7465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if (stop - start == 1) {
7475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // If we have narrowed things down to a single range object, we can
7485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // return from the BPF filter program.
7492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return RetExpression(gen, start->err);
7505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Pick the range object that is located at the mid point of our list.
7535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We compare our system call number against the lowest valid system call
7545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // number in this range object. If our number is lower, it is outside of
7555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // this range object. If it is greater or equal, it might be inside.
7565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Ranges::const_iterator mid = start + (stop - start)/2;
7575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Sub-divide the list of ranges and continue recursively.
7592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Instruction *jf = AssembleJumpTable(gen, start, mid);
7602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Instruction *jt = AssembleJumpTable(gen, mid, stop);
7615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return gen->MakeInstruction(BPF_JMP+BPF_JGE+BPF_K, mid->from, jt, jf);
7625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)Instruction *Sandbox::RetExpression(CodeGen *gen, const ErrorCode& err) {
7652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (err.error_type_ == ErrorCode::ET_COND) {
7662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return CondExpression(gen, err);
7672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  } else {
7682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return gen->MakeInstruction(BPF_RET+BPF_K, err);
7692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
7702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
7712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)Instruction *Sandbox::CondExpression(CodeGen *gen, const ErrorCode& cond) {
7732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // We can only inspect the six system call arguments that are passed in
7742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // CPU registers.
7752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (cond.argno_ < 0 || cond.argno_ >= 6) {
7762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    SANDBOX_DIE("Internal compiler error; invalid argument number "
7772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                "encountered");
7782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
7792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // BPF programs operate on 32bit entities. Load both halfs of the 64bit
7812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // system call argument and then generate suitable conditional statements.
7822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Instruction *msb_head =
7832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    gen->MakeInstruction(BPF_LD+BPF_W+BPF_ABS,
7842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                         SECCOMP_ARG_MSB_IDX(cond.argno_));
7852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Instruction *msb_tail = msb_head;
7862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Instruction *lsb_head =
7872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    gen->MakeInstruction(BPF_LD+BPF_W+BPF_ABS,
7882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                         SECCOMP_ARG_LSB_IDX(cond.argno_));
7892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Instruction *lsb_tail = lsb_head;
7902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Emit a suitable comparison statement.
7922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  switch (cond.op_) {
7932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  case ErrorCode::OP_EQUAL:
7942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Compare the least significant bits for equality
7952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    lsb_tail = gen->MakeInstruction(BPF_JMP+BPF_JEQ+BPF_K,
7962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                    static_cast<uint32_t>(cond.value_),
7972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                    RetExpression(gen, *cond.passed_),
7982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                    RetExpression(gen, *cond.failed_));
7992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    gen->JoinInstructions(lsb_head, lsb_tail);
8002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
8012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // If we are looking at a 64bit argument, we need to also compare the
8022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // most significant bits.
8032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (cond.width_ == ErrorCode::TP_64BIT) {
8042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      msb_tail = gen->MakeInstruction(BPF_JMP+BPF_JEQ+BPF_K,
8052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                      static_cast<uint32_t>(cond.value_ >> 32),
8062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                      lsb_head,
8072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                      RetExpression(gen, *cond.failed_));
8082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      gen->JoinInstructions(msb_head, msb_tail);
8092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
8102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    break;
8112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  case ErrorCode::OP_HAS_ALL_BITS:
8122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Check the bits in the LSB half of the system call argument. Our
8132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // OP_HAS_ALL_BITS operator passes, iff all of the bits are set. This is
8142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // different from the kernel's BPF_JSET operation which passes, if any of
8152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // the bits are set.
8162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Of course, if there is only a single set bit (or none at all), then
8172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // things get easier.
8185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    {
8192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      uint32_t lsb_bits = static_cast<uint32_t>(cond.value_);
8202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      int lsb_bit_count = popcount(lsb_bits);
8212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (lsb_bit_count == 0) {
8222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        // No bits are set in the LSB half. The test will always pass.
8232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        lsb_head = RetExpression(gen, *cond.passed_);
8242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        lsb_tail = NULL;
8252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      } else if (lsb_bit_count == 1) {
8262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        // Exactly one bit is set in the LSB half. We can use the BPF_JSET
8272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        // operator.
8282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        lsb_tail = gen->MakeInstruction(BPF_JMP+BPF_JSET+BPF_K,
8292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                        lsb_bits,
8302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                        RetExpression(gen, *cond.passed_),
8312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                        RetExpression(gen, *cond.failed_));
8322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        gen->JoinInstructions(lsb_head, lsb_tail);
8332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      } else {
8342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        // More than one bit is set in the LSB half. We need to combine
8352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        // BPF_AND and BPF_JEQ to test whether all of these bits are in fact
8362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        // set in the system call argument.
8372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        gen->JoinInstructions(lsb_head,
8382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                     gen->MakeInstruction(BPF_ALU+BPF_AND+BPF_K,
8392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                          lsb_bits,
8402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          lsb_tail = gen->MakeInstruction(BPF_JMP+BPF_JEQ+BPF_K,
8412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                          lsb_bits,
8422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                          RetExpression(gen, *cond.passed_),
8432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                          RetExpression(gen, *cond.failed_))));
8442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      }
8452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
8462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
8472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // If we are looking at a 64bit argument, we need to also check the bits
8482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // in the MSB half of the system call argument.
8492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (cond.width_ == ErrorCode::TP_64BIT) {
8502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      uint32_t msb_bits = static_cast<uint32_t>(cond.value_ >> 32);
8512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      int msb_bit_count = popcount(msb_bits);
8522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (msb_bit_count == 0) {
8532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        // No bits are set in the MSB half. The test will always pass.
8542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        msb_head = lsb_head;
8552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      } else if (msb_bit_count == 1) {
8562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        // Exactly one bit is set in the MSB half. We can use the BPF_JSET
8572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        // operator.
8582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        msb_tail = gen->MakeInstruction(BPF_JMP+BPF_JSET+BPF_K,
8592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                        msb_bits,
8602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                        lsb_head,
8612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                        RetExpression(gen, *cond.failed_));
8622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        gen->JoinInstructions(msb_head, msb_tail);
8632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      } else {
8642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        // More than one bit is set in the MSB half. We need to combine
8652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        // BPF_AND and BPF_JEQ to test whether all of these bits are in fact
8662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        // set in the system call argument.
8672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        gen->JoinInstructions(msb_head,
8682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          gen->MakeInstruction(BPF_ALU+BPF_AND+BPF_K,
8692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                               msb_bits,
8702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          gen->MakeInstruction(BPF_JMP+BPF_JEQ+BPF_K,
8712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                               msb_bits,
8722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                               lsb_head,
8732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                               RetExpression(gen, *cond.failed_))));
8742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      }
8752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
8762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    break;
8772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  case ErrorCode::OP_HAS_ANY_BITS:
8782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Check the bits in the LSB half of the system call argument. Our
8792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // OP_HAS_ANY_BITS operator passes, iff any of the bits are set. This maps
8802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // nicely to the kernel's BPF_JSET operation.
8812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    {
8822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      uint32_t lsb_bits = static_cast<uint32_t>(cond.value_);
8832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (!lsb_bits) {
8842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        // No bits are set in the LSB half. The test will always fail.
8852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        lsb_head = RetExpression(gen, *cond.failed_);
8862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        lsb_tail = NULL;
8872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      } else {
8882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        lsb_tail = gen->MakeInstruction(BPF_JMP+BPF_JSET+BPF_K,
8892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                        lsb_bits,
8902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                        RetExpression(gen, *cond.passed_),
8912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                        RetExpression(gen, *cond.failed_));
8922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        gen->JoinInstructions(lsb_head, lsb_tail);
8932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      }
8945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
8955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // If we are looking at a 64bit argument, we need to also check the bits
8972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // in the MSB half of the system call argument.
8982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (cond.width_ == ErrorCode::TP_64BIT) {
8992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      uint32_t msb_bits = static_cast<uint32_t>(cond.value_ >> 32);
9002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (!msb_bits) {
9012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        // No bits are set in the MSB half. The test will always fail.
9022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        msb_head = lsb_head;
9032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      } else {
9042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        msb_tail = gen->MakeInstruction(BPF_JMP+BPF_JSET+BPF_K,
9052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                        msb_bits,
9062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                        RetExpression(gen, *cond.passed_),
9072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                        lsb_head);
9082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        gen->JoinInstructions(msb_head, msb_tail);
9092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      }
9102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
9112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    break;
9122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  default:
9132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // TODO(markus): Need to add support for OP_GREATER
9142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    SANDBOX_DIE("Not implemented");
9152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    break;
9162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
9175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Ensure that we never pass a 64bit value, when we only expect a 32bit
9192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // value. This is somewhat complicated by the fact that on 64bit systems,
9202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // callers could legitimately pass in a non-zero value in the MSB, iff the
9212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // LSB has been sign-extended into the MSB.
9222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (cond.width_ == ErrorCode::TP_32BIT) {
9232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (cond.value_ >> 32) {
9242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      SANDBOX_DIE("Invalid comparison of a 32bit system call argument "
9252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                  "against a 64bit constant; this test is always false.");
9262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
9275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    Instruction *invalid_64bit = RetExpression(gen, Unexpected64bitArgument());
9292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    #if __SIZEOF_POINTER__ > 4
9302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    invalid_64bit =
9312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      gen->MakeInstruction(BPF_JMP+BPF_JEQ+BPF_K, 0xFFFFFFFF,
9322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      gen->MakeInstruction(BPF_LD+BPF_W+BPF_ABS,
9332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                           SECCOMP_ARG_LSB_IDX(cond.argno_),
9342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      gen->MakeInstruction(BPF_JMP+BPF_JGE+BPF_K, 0x80000000,
9352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                           lsb_head,
9362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                           invalid_64bit)),
9372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                           invalid_64bit);
9382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    #endif
9392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    gen->JoinInstructions(
9402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      msb_tail,
9412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      gen->MakeInstruction(BPF_JMP+BPF_JEQ+BPF_K, 0,
9422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                           lsb_head,
9432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                           invalid_64bit));
9442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
9452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
9462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return msb_head;
9475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)ErrorCode Sandbox::Unexpected64bitArgument() {
9502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return Kill("Unexpected 64bit argument detected");
9512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
9525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)ErrorCode Sandbox::Trap(Trap::TrapFnc fnc, const void *aux) {
9542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return Trap::MakeTrap(fnc, aux, true /* Safe Trap */);
9552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
9565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)ErrorCode Sandbox::UnsafeTrap(Trap::TrapFnc fnc, const void *aux) {
9582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return Trap::MakeTrap(fnc, aux, false /* Unsafe Trap */);
9592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
9605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)intptr_t Sandbox::ForwardSyscall(const struct arch_seccomp_data& args) {
9622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return SandboxSyscall(args.nr,
9632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                        static_cast<intptr_t>(args.args[0]),
9642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                        static_cast<intptr_t>(args.args[1]),
9652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                        static_cast<intptr_t>(args.args[2]),
9662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                        static_cast<intptr_t>(args.args[3]),
9672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                        static_cast<intptr_t>(args.args[4]),
9682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                        static_cast<intptr_t>(args.args[5]));
9695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)ErrorCode Sandbox::Cond(int argno, ErrorCode::ArgType width,
9722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                        ErrorCode::Operation op, uint64_t value,
9732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                        const ErrorCode& passed, const ErrorCode& failed) {
9742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return ErrorCode(argno, width, op, value,
9752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   &*conds_->insert(passed).first,
9762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   &*conds_->insert(failed).first);
9775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ErrorCode Sandbox::Kill(const char *msg) {
9802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return Trap(BpfFailure, const_cast<char *>(msg));
9815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Sandbox::SandboxStatus Sandbox::status_ = STATUS_UNKNOWN;
9845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
986