Bug 920372 - Use Chromium seccomp-bpf compiler to dynamically build sandbox program. r=kang
authorJed Davis <jld@mozilla.com>
Tue, 20 May 2014 18:37:53 -0700
changeset 184042 b56d5602d0cdcc7f06a82538e52fde16aa0d84a3
parent 184041 1541c3c6e894c3162edff99f6a0114c23620d4be
child 184043 2adbb2797d8b4add9ad4db27090d7f6b26d6a3ee
push id26810
push usercbook@mozilla.com
push dateWed, 21 May 2014 11:46:36 +0000
treeherdermozilla-central@50fb8c4db2fd [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskang
bugs920372
milestone32.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 920372 - Use Chromium seccomp-bpf compiler to dynamically build sandbox program. r=kang
security/sandbox/linux/Sandbox.cpp
security/sandbox/linux/SandboxAssembler.cpp
security/sandbox/linux/SandboxAssembler.h
security/sandbox/linux/SandboxFilter.cpp
security/sandbox/linux/SandboxFilter.h
security/sandbox/linux/moz.build
--- a/security/sandbox/linux/Sandbox.cpp
+++ b/security/sandbox/linux/Sandbox.cpp
@@ -42,16 +42,19 @@
 #endif
 
 #ifdef MOZ_LOGGING
 #define FORCE_PR_LOG 1
 #endif
 #include "prlog.h"
 #include "prenv.h"
 
+// See definition of SandboxDie, below.
+#include "sandbox/linux/seccomp-bpf/die.h"
+
 namespace mozilla {
 #if defined(ANDROID)
 #define LOG_ERROR(args...) __android_log_print(ANDROID_LOG_ERROR, "Sandbox", ## args)
 #elif defined(PR_LOGGING)
 static PRLogModuleInfo* gSeccompSandboxLog;
 #define LOG_ERROR(args...) PR_LOG(gSeccompSandboxLog, PR_LOG_ERROR, (args))
 #else
 #define LOG_ERROR(args...)
@@ -201,54 +204,54 @@ InstallSyscallReporter(void)
  * SECCOMP_MODE_FILTER is the "bpf" mode of seccomp which allows
  * to pass a bpf program (in our case, it contains a syscall
  * whitelist).
  *
  * @return 0 on success, 1 on failure.
  * @see sock_fprog (the seccomp_prog).
  */
 static int
-InstallSyscallFilter(void)
+InstallSyscallFilter(const sock_fprog *prog)
 {
 #ifdef MOZ_DMD
   char* e = PR_GetEnv("DMD");
   if (e && strcmp(e, "") != 0 && strcmp(e, "0") != 0) {
     LOG_ERROR("SANDBOX DISABLED FOR DMD!  See bug 956961.");
     // Must treat this as "failure" in order to prevent infinite loop;
     // cf. the PR_GET_SECCOMP check below.
     return 1;
   }
 #endif
   if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) {
     return 1;
   }
 
-  const sock_fprog *filter = GetSandboxFilter();
-
-  if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, (unsigned long)filter, 0, 0)) {
+  if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, (unsigned long)prog, 0, 0)) {
     return 1;
   }
   return 0;
 }
 
 // Use signals for permissions that need to be set per-thread.
 // The communication channel from the signal handler back to the main thread.
 static mozilla::Atomic<int> sSetSandboxDone;
 // about:memory has the first 3 RT signals.  (We should allocate
 // signals centrally instead of hard-coding them like this.)
 static const int sSetSandboxSignum = SIGRTMIN + 3;
+// Pass the filter itself through a global.
+static const sock_fprog *sSetSandboxFilter;
 
 static bool
 SetThreadSandbox()
 {
   bool didAnything = false;
 
   if (PR_GetEnv("MOZ_DISABLE_CONTENT_SANDBOX") == nullptr &&
       prctl(PR_GET_SECCOMP, 0, 0, 0, 0) == 0) {
-    if (InstallSyscallFilter() == 0) {
+    if (InstallSyscallFilter(sSetSandboxFilter) == 0) {
       didAnything = true;
     }
     /*
      * Bug 880797: when all B2G devices are required to support
      * seccomp-bpf, this should exit/crash if InstallSyscallFilter
      * returns nonzero (ifdef MOZ_WIDGET_GONK).
      */
   }
@@ -272,16 +275,18 @@ SetThreadSandboxHandler(int signum)
 }
 
 static void
 BroadcastSetThreadSandbox()
 {
   pid_t pid, tid;
   DIR *taskdp;
   struct dirent *de;
+  SandboxFilter filter(&sSetSandboxFilter,
+                       PR_GetEnv("MOZ_CONTENT_SANDBOX_VERBOSE"));
 
   static_assert(sizeof(mozilla::Atomic<int>) == sizeof(int),
                 "mozilla::Atomic<int> isn't represented by an int");
   MOZ_ASSERT(NS_IsMainThread());
   pid = getpid();
   taskdp = opendir("/proc/self/task");
   if (taskdp == nullptr) {
     LOG_ERROR("opendir /proc/self/task: %s\n", strerror(errno));
@@ -420,8 +425,38 @@ SetCurrentProcessSandbox()
 
   if (IsSandboxingSupported()) {
     BroadcastSetThreadSandbox();
   }
 }
 
 } // namespace mozilla
 
+
+// "Polyfill" for sandbox::Die, the real version of which requires
+// Chromium's logging code.
+namespace sandbox {
+
+void
+Die::SandboxDie(const char* msg, const char* file, int line)
+{
+  LOG_ERROR("%s:%d: %s\n", file, line, msg);
+  _exit(127);
+}
+
+} // namespace sandbox
+
+
+// Stubs for unreached logging calls from Chromium CHECK() macro.
+#include "base/logging.h"
+namespace logging {
+
+LogMessage::LogMessage(const char *file, int line, int)
+  : line_(line), file_(file)
+{
+  MOZ_CRASH("Unexpected call to logging::LogMessage::LogMessage");
+}
+
+LogMessage::~LogMessage() {
+  MOZ_CRASH("Unexpected call to logging::LogMessage::~LogMessage");
+}
+
+} // namespace logging
new file mode 100644
--- /dev/null
+++ b/security/sandbox/linux/SandboxAssembler.cpp
@@ -0,0 +1,150 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "SandboxAssembler.h"
+#include "linux_seccomp.h"
+#include "mozilla/NullPtr.h"
+#include <errno.h>
+
+using namespace sandbox;
+
+namespace mozilla {
+
+SandboxAssembler::SandboxAssembler()
+{
+  mTail = LoadSyscall(nullptr);
+  mTailAlt = nullptr;
+
+  mHead = LoadArch(JmpEq(SECCOMP_ARCH, mTail, RetKill()));
+}
+
+void
+SandboxAssembler::AppendCheck(Instruction *aCheck,
+                              Instruction *aNewTail,
+                              Instruction *aNewTailAlt)
+{
+  mCode.JoinInstructions(mTail, aCheck);
+  if (mTailAlt != nullptr) {
+    mCode.JoinInstructions(mTailAlt, aCheck);
+  }
+  mTail = aNewTail;
+  mTailAlt = aNewTailAlt;
+}
+
+void
+SandboxAssembler::Handle(const Condition &aCond, Instruction *aResult)
+{
+  Instruction *checkArg, *noMatch;
+
+  if (!aCond.mCheckingArg) {
+    checkArg = aResult;
+    noMatch = nullptr;
+  } else {
+    const int8_t arg = aCond.mArgChecked;
+    noMatch = LoadSyscall(nullptr);
+    Instruction *checkArgLo = noMatch;
+
+    // Loop backwards, prepending checks onto the no-match base case.
+    for (size_t i = aCond.mArgValues.size(); i > 0; --i) {
+      checkArgLo = JmpEq(aCond.mArgValues[i - 1], aResult, checkArgLo);
+    }
+    checkArgLo = LoadArgLo(arg, checkArgLo);
+
+    checkArg = LoadArgHi(arg, JmpEq(0, checkArgLo, RetKill()));
+  }
+  Instruction *check = JmpEq(aCond.mSyscallNr, checkArg, nullptr);
+  AppendCheck(check, check, noMatch);
+}
+
+void
+SandboxAssembler::Finish()
+{
+  AppendCheck(RetKill(), nullptr, nullptr);
+}
+
+void
+SandboxAssembler::Compile(std::vector<struct sock_filter> *aProgram,
+                          bool aPrint)
+{
+  mCode.Compile(mHead, aProgram);
+  if (aPrint) {
+    mCode.PrintProgram(*aProgram);
+  }
+}
+
+SandboxAssembler::~SandboxAssembler()
+{
+  // The CodeGen destructor will clean up the Instruction graph.
+}
+
+Instruction *
+SandboxAssembler::LoadArch(Instruction *aNext)
+{
+  return mCode.MakeInstruction(BPF_LD + BPF_W + BPF_ABS,
+                               SECCOMP_ARCH_IDX,
+                               aNext);
+}
+
+Instruction *
+SandboxAssembler::LoadSyscall(Instruction *aNext)
+{
+  return mCode.MakeInstruction(BPF_LD + BPF_W + BPF_ABS,
+                               SECCOMP_NR_IDX,
+                               aNext);
+}
+
+Instruction *
+SandboxAssembler::LoadArgHi(int aArg, Instruction *aNext)
+{
+  return mCode.MakeInstruction(BPF_LD + BPF_W + BPF_ABS,
+                               SECCOMP_ARG_MSB_IDX(aArg),
+                               aNext);
+}
+
+Instruction *
+SandboxAssembler::LoadArgLo(int aArg, Instruction *aNext)
+{
+  return mCode.MakeInstruction(BPF_LD + BPF_W + BPF_ABS,
+                               SECCOMP_ARG_LSB_IDX(aArg),
+                               aNext);
+}
+
+Instruction *
+SandboxAssembler::JmpEq(uint32_t aValue, Instruction *aThen, Instruction *aElse)
+{
+  return mCode.MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K,
+                               aValue, aThen, aElse);
+}
+
+Instruction *
+SandboxAssembler::RetAllow()
+{
+  return mCode.MakeInstruction(BPF_RET + BPF_K,
+                               SECCOMP_RET_ALLOW,
+                               nullptr);
+}
+
+Instruction *
+SandboxAssembler::RetDeny(int aErrno)
+{
+  return mCode.MakeInstruction(BPF_RET + BPF_K,
+                               SECCOMP_RET_ERRNO + aErrno,
+                               nullptr);
+}
+
+Instruction *
+SandboxAssembler::RetKill()
+{
+  return mCode.MakeInstruction(BPF_RET + BPF_K,
+#ifdef MOZ_CONTENT_SANDBOX_REPORTER
+                               SECCOMP_RET_TRAP,
+#else
+                               SECCOMP_RET_KILL,
+#endif
+                               nullptr);
+}
+
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/security/sandbox/linux/SandboxAssembler.h
@@ -0,0 +1,97 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_SandboxAssembler_h
+#define mozilla_SandboxAssembler_h
+
+#include "sandbox/linux/seccomp-bpf/codegen.h"
+
+#include <vector>
+#include "mozilla/Assertions.h"
+
+using namespace sandbox;
+
+namespace mozilla {
+
+class SandboxAssembler {
+public:
+  SandboxAssembler();
+  ~SandboxAssembler();
+
+  class Condition {
+    friend class SandboxAssembler;
+    uint32_t mSyscallNr;
+    bool mCheckingArg;
+    uint8_t mArgChecked;
+    // This class retains a copy of the array, because C++11
+    // initializer_list isn't supported on all relevant platforms.
+    std::vector<uint32_t> mArgValues;
+  public:
+    // Match any instance of the given syscall, with any arguments.
+    explicit Condition(uint32_t aSyscallNr)
+      : mSyscallNr(aSyscallNr)
+      , mCheckingArg(false)
+    { }
+    // Match the syscall only if the given argument is one of the
+    // values in the array specified.  (If the argument isn't
+    // representable as uint32, the process is killed or signaled, as
+    // appropriate.)
+    template<size_t n>
+    Condition(uint32_t aSyscallNr, uint8_t aArgChecked,
+              const uint32_t (&aArgValues)[n])
+      : mSyscallNr(aSyscallNr)
+      , mCheckingArg(true)
+      , mArgChecked(aArgChecked)
+      , mArgValues(aArgValues, aArgValues + n)
+    {
+      MOZ_ASSERT(aArgChecked < sNumArgs);
+    }
+  };
+
+  // Allow syscalls matching this condition, if no earlier condition matched.
+  void Allow(const Condition &aCond) {
+    Handle(aCond, RetAllow());
+  }
+  // Cause syscalls matching this condition to fail with the given error, if
+  // no earlier condition matched.
+  void Deny(int aErrno, const Condition &aCond) {
+    Handle(aCond, RetDeny(aErrno));
+  }
+
+  void Finish();
+  void Compile(std::vector<struct sock_filter> *aProgram,
+               bool aPrint = false);
+private:
+  CodeGen mCode;
+  // The entry point of the filter program.
+  Instruction *mHead;
+  // Pointer to an instruction with a null successor which needs to be filled
+  // in with the rest of the program; see CodeGen::JoinInstructions.
+  Instruction *mTail;
+  // In some cases we will have two such instructions; this, if not null, is
+  // that.  (If we have more complicated conditions in the future, this may
+  // need to be generalized into a vector<Instruction*>.)
+  Instruction *mTailAlt;
+
+  Instruction *RetAllow();
+  Instruction *RetDeny(int aErrno);
+  Instruction *RetKill();
+  Instruction *LoadArch(Instruction *aNext);
+  Instruction *LoadSyscall(Instruction *aNext);
+  Instruction *LoadArgHi(int aArg, Instruction *aNext);
+  Instruction *LoadArgLo(int aArg, Instruction *aNext);
+  Instruction *JmpEq(uint32_t aValue, Instruction *aThen, Instruction *aElse);
+  void AppendCheck(Instruction *aCheck,
+                   Instruction *aNewTail,
+                   Instruction *aNewTailAlt);
+  void Handle(const Condition &aCond, Instruction* aResult);
+
+  static const uint8_t sNumArgs = 6;
+};
+
+}
+
+#endif
--- a/security/sandbox/linux/SandboxFilter.cpp
+++ b/security/sandbox/linux/SandboxFilter.cpp
@@ -1,39 +1,85 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "SandboxFilter.h"
+#include "SandboxAssembler.h"
 
 #include "linux_seccomp.h"
 #include "linux_syscalls.h"
 
 #include "mozilla/ArrayUtils.h"
+#include "mozilla/NullPtr.h"
 
 #include <errno.h>
+#include <unistd.h>
 
 namespace mozilla {
 
-#define SYSCALL_EXISTS(name) defined(__NR_##name)
+class SandboxFilterImpl : public SandboxAssembler
+{
+  void Build();
+public:
+  SandboxFilterImpl() {
+    Build();
+    Finish();
+  }
+};
 
-static struct sock_filter seccomp_filter[] = {
-  VALIDATE_ARCHITECTURE,
-  EXAMINE_SYSCALL,
+SandboxFilter::SandboxFilter(const sock_fprog** aStored, bool aVerbose)
+  : mStored(aStored)
+{
+  MOZ_ASSERT(*mStored == nullptr);
+  std::vector<struct sock_filter> filterVec;
+  {
+    SandboxFilterImpl impl;
+    impl.Compile(&filterVec, aVerbose);
+  }
+  mProg = new sock_fprog;
+  mProg->len = filterVec.size();
+  mProg->filter = mFilter = new sock_filter[mProg->len];
+  for (size_t i = 0; i < mProg->len; ++i) {
+    mFilter[i] = filterVec[i];
+  }
+  *mStored = mProg;
+}
+
+SandboxFilter::~SandboxFilter()
+{
+  *mStored = nullptr;
+  delete[] mFilter;
+  delete mProg;
+}
+
+void
+SandboxFilterImpl::Build() {
+#define SYSCALL_EXISTS(name) (defined(__NR_##name))
+
+#define SYSCALL(name) (Condition(__NR_##name))
+#if defined(__arm__) && (defined(__thumb__) || defined(__ARM_EABI__))
+#define ARM_SYSCALL(name) (Condition(__ARM_NR_##name))
+#endif
+
+#define SYSCALL_WITH_ARG(name, arg, values...) ({ \
+  uint32_t argValues[] = { values };              \
+  Condition(__NR_##name, arg, argValues);         \
+})
 
   // Some architectures went through a transition from 32-bit to
   // 64-bit off_t and had to version all the syscalls that referenced
   // it; others (newer and/or 64-bit ones) didn't.  Adjust the
   // conditional as needed.
 #if SYSCALL_EXISTS(stat64)
-#define ALLOW_SYSCALL_LARGEFILE(plain, versioned) ALLOW_SYSCALL(versioned)
+#define SYSCALL_LARGEFILE(plain, versioned) SYSCALL(versioned)
 #else
-#define ALLOW_SYSCALL_LARGEFILE(plain, versioned) ALLOW_SYSCALL(plain)
+#define SYSCALL_LARGEFILE(plain, versioned) SYSCALL(plain)
 #endif
 
   /* Most used system calls should be at the top of the whitelist
    * for performance reasons. The whitelist BPF filter exits after
    * processing any ALLOW_SYSCALL macro.
    *
    * How are those syscalls found?
    * 1) via strace -p <child pid> or/and
@@ -43,242 +89,225 @@ static struct sock_filter seccomp_filter
    * bionic/libc/kernel/arch-arm/asm/unistd.h
    * or your libc's unistd.h/kernel headers.
    *
    * Current list order has been optimized through manual guess-work.
    * It could be further optimized by analyzing the output of:
    * 'strace -c -p <child pid>' for most used web apps.
    */
 
-  ALLOW_SYSCALL(futex),
+  Allow(SYSCALL(futex));
   // FIXME, bug 920372: i386 multiplexes all the socket-related
   // interfaces into a single syscall.  We should check the selector.
 #if SYSCALL_EXISTS(socketcall)
-  ALLOW_SYSCALL(socketcall),
+  Allow(SYSCALL(socketcall));
 #else
-  ALLOW_SYSCALL(recvmsg),
-  ALLOW_SYSCALL(sendmsg),
+  Allow(SYSCALL(recvmsg));
+  Allow(SYSCALL(sendmsg));
 #endif
 
   // mmap2 is a little different from most off_t users, because it's
   // passed in a register (so it's a problem for even a "new" 32-bit
   // arch) -- and the workaround, mmap2, passes a page offset instead.
 #if SYSCALL_EXISTS(mmap2)
-  ALLOW_SYSCALL(mmap2),
+  Allow(SYSCALL(mmap2));
 #else
-  ALLOW_SYSCALL(mmap),
+  Allow(SYSCALL(mmap));
 #endif
 
   /* B2G specific high-frequency syscalls */
 #ifdef MOZ_WIDGET_GONK
-  ALLOW_SYSCALL(clock_gettime),
-  ALLOW_SYSCALL(epoll_wait),
-  ALLOW_SYSCALL(gettimeofday),
+  Allow(SYSCALL(clock_gettime));
+  Allow(SYSCALL(epoll_wait));
+  Allow(SYSCALL(gettimeofday));
 #endif
-  ALLOW_SYSCALL(read),
-  ALLOW_SYSCALL(write),
+  Allow(SYSCALL(read));
+  Allow(SYSCALL(write));
   // 32-bit lseek is used, at least on Android, to implement ANSI fseek.
 #if SYSCALL_EXISTS(_llseek)
-  ALLOW_SYSCALL(_llseek),
+  Allow(SYSCALL(_llseek));
 #endif
-  ALLOW_SYSCALL(lseek),
+  Allow(SYSCALL(lseek));
   // Android also uses 32-bit ftruncate.
-  ALLOW_SYSCALL(ftruncate),
+  Allow(SYSCALL(ftruncate));
 #if SYSCALL_EXISTS(ftruncate64)
-  ALLOW_SYSCALL(ftruncate64),
+  Allow(SYSCALL(ftruncate64));
 #endif
 
   /* ioctl() is for GL. Remove when GL proxy is implemented.
    * Additionally ioctl() might be a place where we want to have
    * argument filtering */
-  ALLOW_SYSCALL(ioctl),
-  ALLOW_SYSCALL(close),
-  ALLOW_SYSCALL(munmap),
-  ALLOW_SYSCALL(mprotect),
-  ALLOW_SYSCALL(writev),
-  ALLOW_SYSCALL(clone),
-  ALLOW_SYSCALL(brk),
+  Allow(SYSCALL(ioctl));
+  Allow(SYSCALL(close));
+  Allow(SYSCALL(munmap));
+  Allow(SYSCALL(mprotect));
+  Allow(SYSCALL(writev));
+  Allow(SYSCALL(clone));
+  Allow(SYSCALL(brk));
 #if SYSCALL_EXISTS(set_thread_area)
-  ALLOW_SYSCALL(set_thread_area),
+  Allow(SYSCALL(set_thread_area));
 #endif
 
-  ALLOW_SYSCALL(getpid),
-  ALLOW_SYSCALL(gettid),
-  ALLOW_SYSCALL(getrusage),
-  ALLOW_SYSCALL(madvise),
-  ALLOW_SYSCALL(dup),
-  ALLOW_SYSCALL(nanosleep),
-  ALLOW_SYSCALL(poll),
+  Allow(SYSCALL(getpid));
+  Allow(SYSCALL(gettid));
+  Allow(SYSCALL(getrusage));
+  Allow(SYSCALL(madvise));
+  Allow(SYSCALL(dup));
+  Allow(SYSCALL(nanosleep));
+  Allow(SYSCALL(poll));
   // select()'s arguments used to be passed by pointer as a struct.
 #if SYSCALL_EXISTS(_newselect)
-  ALLOW_SYSCALL(_newselect),
+  Allow(SYSCALL(_newselect));
 #else
-  ALLOW_SYSCALL(select),
+  Allow(SYSCALL(select));
 #endif
   // Some archs used to have 16-bit uid/gid instead of 32-bit.
 #if SYSCALL_EXISTS(getuid32)
-  ALLOW_SYSCALL(getuid32),
-  ALLOW_SYSCALL(geteuid32),
+  Allow(SYSCALL(getuid32));
+  Allow(SYSCALL(geteuid32));
 #else
-  ALLOW_SYSCALL(getuid),
-  ALLOW_SYSCALL(geteuid),
+  Allow(SYSCALL(getuid));
+  Allow(SYSCALL(geteuid));
 #endif
   // Some newer archs (e.g., x64 and x32) have only rt_sigreturn, but
   // ARM has and uses both syscalls -- rt_sigreturn for SA_SIGINFO
   // handlers and classic sigreturn otherwise.
 #if SYSCALL_EXISTS(sigreturn)
-  ALLOW_SYSCALL(sigreturn),
+  Allow(SYSCALL(sigreturn));
 #endif
-  ALLOW_SYSCALL(rt_sigreturn),
-  ALLOW_SYSCALL_LARGEFILE(fcntl, fcntl64),
+  Allow(SYSCALL(rt_sigreturn));
+  Allow(SYSCALL_LARGEFILE(fcntl, fcntl64));
 
   /* Must remove all of the following in the future, when no longer used */
   /* open() is for some legacy APIs such as font loading. */
   /* See bug 906996 for removing unlink(). */
-  ALLOW_SYSCALL_LARGEFILE(fstat, fstat64),
-  ALLOW_SYSCALL_LARGEFILE(stat, stat64),
-  ALLOW_SYSCALL_LARGEFILE(lstat, lstat64),
+  Allow(SYSCALL_LARGEFILE(fstat, fstat64));
+  Allow(SYSCALL_LARGEFILE(stat, stat64));
+  Allow(SYSCALL_LARGEFILE(lstat, lstat64));
   // FIXME, bug 920372: see above.
 #if !SYSCALL_EXISTS(socketcall)
-  ALLOW_SYSCALL(socketpair),
-  DENY_SYSCALL(socket, EACCES),
+  Allow(SYSCALL(socketpair));
+  Deny(EACCES, SYSCALL(socket));
 #endif
-  ALLOW_SYSCALL(open),
-  ALLOW_SYSCALL(readlink), /* Workaround for bug 964455 */
-  ALLOW_SYSCALL(prctl),
-  ALLOW_SYSCALL(access),
-  ALLOW_SYSCALL(unlink),
-  ALLOW_SYSCALL(fsync),
-  ALLOW_SYSCALL(msync),
+  Allow(SYSCALL(open));
+  Allow(SYSCALL(readlink)); /* Workaround for bug 964455 */
+  Allow(SYSCALL(prctl));
+  Allow(SYSCALL(access));
+  Allow(SYSCALL(unlink));
+  Allow(SYSCALL(fsync));
+  Allow(SYSCALL(msync));
 
   /* Should remove all of the following in the future, if possible */
-  ALLOW_SYSCALL(getpriority),
-  ALLOW_SYSCALL(sched_get_priority_min),
-  ALLOW_SYSCALL(sched_get_priority_max),
-  ALLOW_SYSCALL(setpriority),
+  Allow(SYSCALL(getpriority));
+  Allow(SYSCALL(sched_get_priority_min));
+  Allow(SYSCALL(sched_get_priority_max));
+  Allow(SYSCALL(setpriority));
   // rt_sigprocmask is passed the sigset_t size.  On older archs,
   // sigprocmask is a compatibility shim that assumes the pre-RT size.
 #if SYSCALL_EXISTS(sigprocmask)
-  ALLOW_SYSCALL(sigprocmask),
+  Allow(SYSCALL(sigprocmask));
 #endif
-  ALLOW_SYSCALL(rt_sigprocmask),
+  Allow(SYSCALL(rt_sigprocmask));
 
   // Used by profiler.  Also used for raise(), which causes problems
   // with Android KitKat abort(); see bug 1004832.
-  ALLOW_SYSCALL(tgkill),
+  Allow(SYSCALL(tgkill));
 
   /* B2G specific low-frequency syscalls */
 #ifdef MOZ_WIDGET_GONK
 #if !SYSCALL_EXISTS(socketcall)
-  ALLOW_SYSCALL(sendto),
-  ALLOW_SYSCALL(recvfrom),
+  Allow(SYSCALL(sendto));
+  Allow(SYSCALL(recvfrom));
 #endif
-  ALLOW_SYSCALL_LARGEFILE(getdents, getdents64),
-  ALLOW_SYSCALL(epoll_ctl),
-  ALLOW_SYSCALL(sched_yield),
-  ALLOW_SYSCALL(sched_getscheduler),
-  ALLOW_SYSCALL(sched_setscheduler),
-  ALLOW_SYSCALL(sigaltstack),
+  Allow(SYSCALL_LARGEFILE(getdents, getdents64));
+  Allow(SYSCALL(epoll_ctl));
+  Allow(SYSCALL(sched_yield));
+  Allow(SYSCALL(sched_getscheduler));
+  Allow(SYSCALL(sched_setscheduler));
+  Allow(SYSCALL(sigaltstack));
 #endif
 
   /* Always last and always OK calls */
   /* Architecture-specific very infrequently used syscalls */
 #if SYSCALL_EXISTS(sigaction)
-  ALLOW_SYSCALL(sigaction),
+  Allow(SYSCALL(sigaction));
 #endif
-  ALLOW_SYSCALL(rt_sigaction),
-#ifdef ALLOW_ARM_SYSCALL
-  ALLOW_ARM_SYSCALL(breakpoint),
-  ALLOW_ARM_SYSCALL(cacheflush),
-  ALLOW_ARM_SYSCALL(usr26),
-  ALLOW_ARM_SYSCALL(usr32),
-  ALLOW_ARM_SYSCALL(set_tls),
+  Allow(SYSCALL(rt_sigaction));
+#ifdef ARM_SYSCALL
+  Allow(ARM_SYSCALL(breakpoint));
+  Allow(ARM_SYSCALL(cacheflush));
+  Allow(ARM_SYSCALL(usr26));
+  Allow(ARM_SYSCALL(usr32));
+  Allow(ARM_SYSCALL(set_tls));
 #endif
 
   /* restart_syscall is called internally, generally when debugging */
-  ALLOW_SYSCALL(restart_syscall),
+  Allow(SYSCALL(restart_syscall));
 
   /* linux desktop is not as performance critical as B2G */
   /* we can place desktop syscalls at the end */
 #ifndef MOZ_WIDGET_GONK
-  ALLOW_SYSCALL(stat),
-  ALLOW_SYSCALL(getdents),
-  ALLOW_SYSCALL(lstat),
-  ALLOW_SYSCALL(mmap),
-  ALLOW_SYSCALL(openat),
-  ALLOW_SYSCALL(fcntl),
-  ALLOW_SYSCALL(fstat),
-  ALLOW_SYSCALL(readlink),
-  ALLOW_SYSCALL(getsockname),
-  ALLOW_SYSCALL(getuid),
-  ALLOW_SYSCALL(geteuid),
-  ALLOW_SYSCALL(mkdir),
-  ALLOW_SYSCALL(getcwd),
-  ALLOW_SYSCALL(readahead),
-  ALLOW_SYSCALL(pread64),
-  ALLOW_SYSCALL(statfs),
-  ALLOW_SYSCALL(pipe),
-  ALLOW_SYSCALL(getrlimit),
-  ALLOW_SYSCALL(shutdown),
-  ALLOW_SYSCALL(getpeername),
-  ALLOW_SYSCALL(eventfd2),
-  ALLOW_SYSCALL(clock_getres),
-  ALLOW_SYSCALL(sysinfo),
-  ALLOW_SYSCALL(getresuid),
-  ALLOW_SYSCALL(umask),
-  ALLOW_SYSCALL(getresgid),
-  ALLOW_SYSCALL(poll),
-  ALLOW_SYSCALL(getegid),
-  ALLOW_SYSCALL(inotify_init1),
-  ALLOW_SYSCALL(wait4),
-  ALLOW_SYSCALL(shmctl),
-  ALLOW_SYSCALL(set_robust_list),
-  ALLOW_SYSCALL(rmdir),
-  ALLOW_SYSCALL(recvfrom),
-  ALLOW_SYSCALL(shmdt),
-  ALLOW_SYSCALL(pipe2),
-  ALLOW_SYSCALL(setsockopt),
-  ALLOW_SYSCALL(shmat),
-  ALLOW_SYSCALL(set_tid_address),
-  ALLOW_SYSCALL(inotify_add_watch),
-  ALLOW_SYSCALL(rt_sigprocmask),
-  ALLOW_SYSCALL(shmget),
-  ALLOW_SYSCALL(getgid),
-  ALLOW_SYSCALL(utime),
-  ALLOW_SYSCALL(arch_prctl),
-  ALLOW_SYSCALL(sched_getaffinity),
+  Allow(SYSCALL(stat));
+  Allow(SYSCALL(getdents));
+  Allow(SYSCALL(lstat));
+  Allow(SYSCALL(mmap));
+  Allow(SYSCALL(openat));
+  Allow(SYSCALL(fcntl));
+  Allow(SYSCALL(fstat));
+  Allow(SYSCALL(readlink));
+  Allow(SYSCALL(getsockname));
+  Allow(SYSCALL(getuid));
+  Allow(SYSCALL(geteuid));
+  Allow(SYSCALL(mkdir));
+  Allow(SYSCALL(getcwd));
+  Allow(SYSCALL(readahead));
+  Allow(SYSCALL(pread64));
+  Allow(SYSCALL(statfs));
+  Allow(SYSCALL(pipe));
+  Allow(SYSCALL(getrlimit));
+  Allow(SYSCALL(shutdown));
+  Allow(SYSCALL(getpeername));
+  Allow(SYSCALL(eventfd2));
+  Allow(SYSCALL(clock_getres));
+  Allow(SYSCALL(sysinfo));
+  Allow(SYSCALL(getresuid));
+  Allow(SYSCALL(umask));
+  Allow(SYSCALL(getresgid));
+  Allow(SYSCALL(poll));
+  Allow(SYSCALL(getegid));
+  Allow(SYSCALL(inotify_init1));
+  Allow(SYSCALL(wait4));
+  Allow(SYSCALL(shmctl));
+  Allow(SYSCALL(set_robust_list));
+  Allow(SYSCALL(rmdir));
+  Allow(SYSCALL(recvfrom));
+  Allow(SYSCALL(shmdt));
+  Allow(SYSCALL(pipe2));
+  Allow(SYSCALL(setsockopt));
+  Allow(SYSCALL(shmat));
+  Allow(SYSCALL(set_tid_address));
+  Allow(SYSCALL(inotify_add_watch));
+  Allow(SYSCALL(rt_sigprocmask));
+  Allow(SYSCALL(shmget));
+  Allow(SYSCALL(getgid));
+  Allow(SYSCALL(utime));
+  Allow(SYSCALL(arch_prctl));
+  Allow(SYSCALL(sched_getaffinity));
   /* We should remove all of the following in the future (possibly even more) */
-  ALLOW_SYSCALL(socket),
-  ALLOW_SYSCALL(chmod),
-  ALLOW_SYSCALL(execve),
-  ALLOW_SYSCALL(rename),
-  ALLOW_SYSCALL(symlink),
-  ALLOW_SYSCALL(connect),
-  ALLOW_SYSCALL(quotactl),
-  ALLOW_SYSCALL(kill),
-  ALLOW_SYSCALL(sendto),
+  Allow(SYSCALL(socket));
+  Allow(SYSCALL(chmod));
+  Allow(SYSCALL(execve));
+  Allow(SYSCALL(rename));
+  Allow(SYSCALL(symlink));
+  Allow(SYSCALL(connect));
+  Allow(SYSCALL(quotactl));
+  Allow(SYSCALL(kill));
+  Allow(SYSCALL(sendto));
 #endif
 
   /* nsSystemInfo uses uname (and we cache an instance, so */
   /* the info remains present even if we block the syscall) */
-  ALLOW_SYSCALL(uname),
-  ALLOW_SYSCALL(exit_group),
-  ALLOW_SYSCALL(exit),
-
-#ifdef MOZ_CONTENT_SANDBOX_REPORTER
-  TRAP_PROCESS,
-#else
-  KILL_PROCESS,
-#endif
-};
-
-static struct sock_fprog seccomp_prog = {
-  (unsigned short)MOZ_ARRAY_LENGTH(seccomp_filter),
-  seccomp_filter,
-};
-
-const sock_fprog*
-GetSandboxFilter()
-{
-  return &seccomp_prog;
+  Allow(SYSCALL(uname));
+  Allow(SYSCALL(exit_group));
+  Allow(SYSCALL(exit));
 }
 
 }
--- a/security/sandbox/linux/SandboxFilter.h
+++ b/security/sandbox/linux/SandboxFilter.h
@@ -3,16 +3,25 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_SandboxFilter_h
 #define mozilla_SandboxFilter_h
 
 struct sock_fprog;
+struct sock_filter;
 
 namespace mozilla {
-
-const sock_fprog* GetSandboxFilter();
-
+  class SandboxFilter {
+    sock_filter *mFilter;
+    sock_fprog *mProg;
+    const sock_fprog **mStored;
+  public:
+  // RAII: on construction, builds the filter and stores it in the
+  // provided variable (with optional logging); on destruction, frees
+  // the filter and nulls out the pointer.
+    SandboxFilter(const sock_fprog** aStored, bool aVerbose = false);
+    ~SandboxFilter();
+  };
 }
 
 #endif
--- a/security/sandbox/linux/moz.build
+++ b/security/sandbox/linux/moz.build
@@ -6,15 +6,20 @@
 
 FAIL_ON_WARNINGS = True
 
 EXPORTS.mozilla += [
     'Sandbox.h',
 ]
 
 SOURCES += [
+    '../chromium/sandbox/linux/seccomp-bpf/basicblock.cc',
+    '../chromium/sandbox/linux/seccomp-bpf/codegen.cc',
     'Sandbox.cpp',
+    'SandboxAssembler.cpp',
     'SandboxFilter.cpp',
 ]
 
+LOCAL_INCLUDES += ['/security/sandbox/chromium']
+
 include('/ipc/chromium/chromium-config.mozbuild')
 
 FINAL_LIBRARY = 'xul'