Bug 1012951 - Add Linux sandboxing for GeckoMediaPlugin processes. r=kang r=ted
authorJed Davis <jld@mozilla.com>
Mon, 04 Aug 2014 15:11:18 -0700
changeset 219398 b60e4395f1413e062b19e22dd16da68983719219
parent 219397 d78784f732eb181c05e0c8759fe959e2bcf7ff49
child 219399 36cf6a98d663a59eb03043e62527b120fc876e1d
push id3979
push userraliiev@mozilla.com
push dateMon, 13 Oct 2014 16:35:44 +0000
treeherdermozilla-beta@30f2cc610691 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskang, ted
bugs1012951
milestone34.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 1012951 - Add Linux sandboxing for GeckoMediaPlugin processes. r=kang r=ted
configure.in
content/media/gmp/GMPChild.cpp
dom/ipc/ContentChild.cpp
security/sandbox/linux/Sandbox.cpp
security/sandbox/linux/Sandbox.h
security/sandbox/linux/SandboxFilter.cpp
security/sandbox/linux/SandboxFilter.h
toolkit/toolkit.mozbuild
--- a/configure.in
+++ b/configure.in
@@ -3838,16 +3838,17 @@ MOZ_LOCALE_SWITCHER=
 MOZ_ANDROID_SEARCH_ACTIVITY=
 MOZ_ANDROID_MLS_STUMBLER=
 ACCESSIBILITY=1
 MOZ_TIME_MANAGER=
 MOZ_PAY=
 MOZ_AUDIO_CHANNEL_MANAGER=
 NSS_NO_LIBPKIX=
 MOZ_CONTENT_SANDBOX=
+MOZ_GMP_SANDBOX=
 JSGC_USE_EXACT_ROOTING=1
 JSGC_GENERATIONAL=
 
 case "$target_os" in
     mingw*)
         NS_ENABLE_TSF=1
         AC_DEFINE(NS_ENABLE_TSF)
         ;;
@@ -6390,16 +6391,38 @@ MOZ_ARG_ENABLE_BOOL(content-sandbox,
 
 if test -n "$MOZ_CONTENT_SANDBOX"; then
     AC_DEFINE(MOZ_CONTENT_SANDBOX)
 fi
 
 AC_SUBST(MOZ_CONTENT_SANDBOX)
 
 dnl ========================================================
+dnl = Gecko Media Plugin sandboxing
+dnl ========================================================
+case $OS_TARGET in
+WINNT)
+    MOZ_GMP_SANDBOX=1
+    ;;
+Linux)
+    case $CPU_ARCH in
+    x86_64|x86)
+        MOZ_GMP_SANDBOX=1
+        ;;
+    esac
+    ;;
+esac
+
+if test -n "$MOZ_GMP_SANDBOX"; then
+    AC_DEFINE(MOZ_GMP_SANDBOX)
+fi
+
+AC_SUBST(MOZ_GMP_SANDBOX)
+
+dnl ========================================================
 dnl =
 dnl = Module specific options
 dnl =
 dnl ========================================================
 MOZ_ARG_HEADER(Individual module options)
 
 dnl ========================================================
 dnl = Disable feed handling components
--- a/content/media/gmp/GMPChild.cpp
+++ b/content/media/gmp/GMPChild.cpp
@@ -22,16 +22,18 @@ using mozilla::dom::CrashReporterChild;
 #include <stdlib.h> // for _exit()
 #else
 #include <unistd.h> // for _exit()
 #endif
 
 #if defined(XP_WIN)
 #define TARGET_SANDBOX_EXPORTS
 #include "mozilla/sandboxTarget.h"
+#elif defined(XP_LINUX) && defined(MOZ_GMP_SANDBOX)
+#include "mozilla/Sandbox.h"
 #endif
 
 namespace mozilla {
 namespace gmp {
 
 GMPChild::GMPChild()
   : mLib(nullptr)
   , mGetAPIFunc(nullptr)
@@ -94,16 +96,23 @@ GMPChild::LoadPluginLibrary(const std::s
   nsAutoString binaryName =                            baseName + NS_LITERAL_STRING(".dll");
 #else
 #error not defined
 #endif
   libFile->AppendRelativePath(binaryName);
 
   nsAutoCString nativePath;
   libFile->GetNativePath(nativePath);
+
+#if defined(XP_LINUX) && defined(MOZ_GMP_SANDBOX)
+  // Enable sandboxing here -- we know the plugin file's path, but
+  // this process's execution hasn't been affected by its content yet.
+  mozilla::SetMediaPluginSandbox(nativePath.get());
+#endif
+
   mLib = PR_LoadLibrary(nativePath.get());
   if (!mLib) {
     return false;
   }
 
   GMPInitFunc initFunc = reinterpret_cast<GMPInitFunc>(PR_FindFunctionSymbol(mLib, "GMPInit"));
   if (!initFunc) {
     return false;
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -913,17 +913,17 @@ ContentChild::AllocPBackgroundChild(Tran
 
 bool
 ContentChild::RecvSetProcessSandbox()
 {
   // We may want to move the sandbox initialization somewhere else
   // at some point; see bug 880808.
 #if defined(MOZ_CONTENT_SANDBOX)
 #if defined(XP_LINUX)
-    SetCurrentProcessSandbox();
+    SetContentProcessSandbox();
 #elif defined(XP_WIN)
     mozilla::SandboxTarget::Instance()->StartSandbox();
 #endif
 #endif
     return true;
 }
 
 bool
--- a/security/sandbox/linux/Sandbox.cpp
+++ b/security/sandbox/linux/Sandbox.cpp
@@ -14,49 +14,55 @@
 #include <signal.h>
 #include <string.h>
 #include <linux/futex.h>
 #include <sys/time.h>
 #include <dirent.h>
 #include <stdlib.h>
 #include <pthread.h>
 #include <errno.h>
+#include <fcntl.h>
 
 #include "mozilla/Atomics.h"
 #include "mozilla/NullPtr.h"
 #include "mozilla/unused.h"
 #include "mozilla/dom/Exceptions.h"
-#include "nsString.h"
 #include "nsThreadUtils.h"
 #include "prenv.h"
 
 #ifdef MOZ_CRASHREPORTER
 #include "nsExceptionHandler.h"
 #endif
 
 #if defined(ANDROID)
 #include "android_ucontext.h"
 #include <android/log.h>
 #endif
 
-#if defined(MOZ_CONTENT_SANDBOX)
 #include "linux_seccomp.h"
 #include "SandboxFilter.h"
-#endif
 
 // 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)
 #else
 #define LOG_ERROR(fmt, args...) fprintf(stderr, "Sandbox: " fmt, ## args)
 #endif
 
+#ifdef MOZ_GMP_SANDBOX
+// For media plugins, we can start the sandbox before we dlopen the
+// module, so we have to pre-open the file and simulate the sandboxed
+// open().
+static int gMediaPluginFileDesc = -1;
+static const char *gMediaPluginFilePath;
+#endif
+
 /**
  * Log JS stack info in the same place as the sandbox violation
  * message.  Useful in case the responsible code is JS and all we have
  * are logs and a minidump with the C++ stacks (e.g., on TBPL).
  */
 static void
 SandboxLogJSStack(void)
 {
@@ -124,16 +130,37 @@ Reporter(int nr, siginfo_t *info, void *
   syscall_nr = SECCOMP_SYSCALL(ctx);
   args[0] = SECCOMP_PARM1(ctx);
   args[1] = SECCOMP_PARM2(ctx);
   args[2] = SECCOMP_PARM3(ctx);
   args[3] = SECCOMP_PARM4(ctx);
   args[4] = SECCOMP_PARM5(ctx);
   args[5] = SECCOMP_PARM6(ctx);
 
+#ifdef MOZ_GMP_SANDBOX
+  if (syscall_nr == __NR_open && gMediaPluginFilePath) {
+    const char *path = reinterpret_cast<const char*>(args[0]);
+    int flags = int(args[1]);
+
+    if ((flags & O_ACCMODE) != O_RDONLY) {
+      LOG_ERROR("non-read-only open of file %s attempted (flags=0%o)",
+                path, flags);
+    } else if (strcmp(path, gMediaPluginFilePath) != 0) {
+      LOG_ERROR("attempt to open file %s which is not the media plugin %s",
+                path, gMediaPluginFilePath);
+    } else if (gMediaPluginFileDesc == -1) {
+      LOG_ERROR("multiple opens of media plugin file unimplemented");
+    } else {
+      SECCOMP_RESULT(ctx) = gMediaPluginFileDesc;
+      gMediaPluginFileDesc = -1;
+      return;
+    }
+  }
+#endif
+
   LOG_ERROR("seccomp sandbox violation: pid %d, syscall %lu, args %lu %lu %lu"
             " %lu %lu %lu.  Killing process.", pid, syscall_nr,
             args[0], args[1], args[2], args[3], args[4], args[5]);
 
 #ifdef MOZ_CRASHREPORTER
   // Bug 1017393: record syscall number somewhere useful.
   info->si_addr = reinterpret_cast<void*>(syscall_nr);
   bool dumped = CrashReporter::WriteMinidumpForSigInfo(nr, info, void_context);
@@ -241,18 +268,17 @@ FindFreeSignalNumber()
   return 0;
 }
 
 static bool
 SetThreadSandbox()
 {
   bool didAnything = false;
 
-  if (PR_GetEnv("MOZ_DISABLE_CONTENT_SANDBOX") == nullptr &&
-      prctl(PR_GET_SECCOMP, 0, 0, 0, 0) == 0) {
+  if (prctl(PR_GET_SECCOMP, 0, 0, 0, 0) == 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,29 +298,29 @@ SetThreadSandboxHandler(int signum)
   }
   // Wake up the main thread.  See the FUTEX_WAIT call, below, for an
   // explanation.
   syscall(__NR_futex, reinterpret_cast<int*>(&sSetSandboxDone),
           FUTEX_WAKE, 1);
 }
 
 static void
-BroadcastSetThreadSandbox()
+BroadcastSetThreadSandbox(SandboxType aType)
 {
   int signum;
-  pid_t pid, tid;
+  pid_t pid, tid, myTid;
   DIR *taskdp;
   struct dirent *de;
-  SandboxFilter filter(&sSetSandboxFilter,
-                       PR_GetEnv("MOZ_CONTENT_SANDBOX_VERBOSE"));
+  SandboxFilter filter(&sSetSandboxFilter, aType,
+                       PR_GetEnv("MOZ_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();
+  myTid = syscall(__NR_gettid);
   taskdp = opendir("/proc/self/task");
   if (taskdp == nullptr) {
     LOG_ERROR("opendir /proc/self/task: %s\n", strerror(errno));
     MOZ_CRASH();
   }
   signum = FindFreeSignalNumber();
   if (signum == 0) {
     LOG_ERROR("No available signal numbers!");
@@ -317,19 +343,19 @@ BroadcastSetThreadSandbox()
     // For each thread...
     while ((de = readdir(taskdp))) {
       char *endptr;
       tid = strtol(de->d_name, &endptr, 10);
       if (*endptr != '\0' || tid <= 0) {
         // Not a task ID.
         continue;
       }
-      if (tid == pid) {
-        // Drop the main thread's privileges last, below, so
-        // we can continue to signal other threads.
+      if (tid == myTid) {
+        // Drop this thread's privileges last, below, so we can
+        // continue to signal other threads.
         continue;
       }
       // Reset the futex cell and signal.
       sSetSandboxDone = 0;
       if (syscall(__NR_tgkill, pid, tid, signum) != 0) {
         if (errno == ESRCH) {
           LOG_ERROR("Thread %d unexpectedly exited.", tid);
           // Rescan threads, in case it forked before exiting.
@@ -412,34 +438,79 @@ BroadcastSetThreadSandbox()
 // This function can overapproximate (i.e., return true even if
 // sandboxing isn't supported, but not the reverse).  See bug 993145.
 static bool
 IsSandboxingSupported(void)
 {
   return prctl(PR_GET_SECCOMP) != -1;
 }
 
-/**
- * Starts the seccomp sandbox for this process and sets user/group-based privileges.
- * Should be called only once, and before any potentially harmful content is loaded.
- *
- * Should normally make the process exit on failure.
-*/
-void
-SetCurrentProcessSandbox()
+// Common code for sandbox startup.
+static void
+SetCurrentProcessSandbox(SandboxType aType)
 {
   if (InstallSyscallReporter()) {
     LOG_ERROR("install_syscall_reporter() failed\n");
   }
 
   if (IsSandboxingSupported()) {
-    BroadcastSetThreadSandbox();
+    BroadcastSetThreadSandbox(aType);
   }
 }
 
+#ifdef MOZ_CONTENT_SANDBOX
+/**
+ * Starts the seccomp sandbox for a content process.  Should be called
+ * only once, and before any potentially harmful content is loaded.
+ *
+ * Will normally make the process exit on failure.
+*/
+void
+SetContentProcessSandbox()
+{
+  if (PR_GetEnv("MOZ_DISABLE_CONTENT_SANDBOX")) {
+    return;
+  }
+
+  SetCurrentProcessSandbox(kSandboxContentProcess);
+}
+#endif // MOZ_CONTENT_SANDBOX
+
+#ifdef MOZ_GMP_SANDBOX
+/**
+ * Starts the seccomp sandbox for a media plugin process.  Should be
+ * called only once, and before any potentially harmful content is
+ * loaded -- including the plugin itself, if it's considered untrusted.
+ *
+ * The file indicated by aFilePath, if non-null, can be open()ed once
+ * read-only after the sandbox starts; it should be the .so file
+ * implementing the not-yet-loaded plugin.
+ *
+ * Will normally make the process exit on failure.
+*/
+void
+SetMediaPluginSandbox(const char *aFilePath)
+{
+  if (PR_GetEnv("MOZ_DISABLE_GMP_SANDBOX")) {
+    return;
+  }
+
+  if (aFilePath) {
+    gMediaPluginFilePath = strdup(aFilePath);
+    gMediaPluginFileDesc = open(aFilePath, O_RDONLY | O_CLOEXEC);
+    if (gMediaPluginFileDesc == -1) {
+      LOG_ERROR("failed to open plugin file %s: %s", aFilePath, strerror(errno));
+      MOZ_CRASH();
+    }
+  }
+  // Finally, start the sandbox.
+  SetCurrentProcessSandbox(kSandboxMediaPlugin);
+}
+#endif // MOZ_GMP_SANDBOX
+
 } // namespace mozilla
 
 
 // "Polyfill" for sandbox::Die, the real version of which requires
 // Chromium's logging code.
 namespace sandbox {
 
 void
--- a/security/sandbox/linux/Sandbox.h
+++ b/security/sandbox/linux/Sandbox.h
@@ -4,14 +4,19 @@
  * 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_Sandbox_h
 #define mozilla_Sandbox_h
 
 namespace mozilla {
 
-void SetCurrentProcessSandbox();
+#ifdef MOZ_CONTENT_SANDBOX
+void SetContentProcessSandbox();
+#endif
+#ifdef MOZ_GMP_SANDBOX
+void SetMediaPluginSandbox(const char *aFilePath);
+#endif
 
 } // namespace mozilla
 
 #endif // mozilla_Sandbox_h
 
--- a/security/sandbox/linux/SandboxFilter.cpp
+++ b/security/sandbox/linux/SandboxFilter.cpp
@@ -9,97 +9,82 @@
 
 #include "linux_seccomp.h"
 #include "linux_syscalls.h"
 
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/NullPtr.h"
 
 #include <errno.h>
-#include <unistd.h>
+#include <linux/ipc.h>
 #include <linux/net.h>
-#include <linux/ipc.h>
+#include <linux/prctl.h>
+#include <linux/sched.h>
+#include <sys/mman.h>
+#include <time.h>
+#include <unistd.h>
 
 namespace mozilla {
 
 class SandboxFilterImpl : public SandboxAssembler
 {
-  void Build();
 public:
-  SandboxFilterImpl() {
-    Build();
-    Finish();
-  }
+  virtual void Build() = 0;
+  virtual ~SandboxFilterImpl() { }
 };
 
-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;
-}
+// Some helper macros to make the code that builds the filter more
+// readable, and to help deal with differences among architectures.
 
-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.
+// 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 SYSCALL_LARGEFILE(plain, versioned) SYSCALL(versioned)
 #else
 #define SYSCALL_LARGEFILE(plain, versioned) SYSCALL(plain)
 #endif
 
-  // i386 multiplexes all the socket-related interfaces into a single
-  // syscall.
+// i386 multiplexes all the socket-related interfaces into a single
+// syscall.
 #if SYSCALL_EXISTS(socketcall)
 #define SOCKETCALL(name, NAME) SYSCALL_WITH_ARG(socketcall, 0, SYS_##NAME)
 #else
 #define SOCKETCALL(name, NAME) SYSCALL(name)
 #endif
 
-  // i386 multiplexes all the SysV-IPC-related interfaces into a single
-  // syscall.
+// i386 multiplexes all the SysV-IPC-related interfaces into a single
+// syscall.
 #if SYSCALL_EXISTS(ipc)
 #define SYSVIPCCALL(name, NAME) SYSCALL_WITH_ARG(ipc, 0, NAME)
 #else
 #define SYSVIPCCALL(name, NAME) SYSCALL(name)
 #endif
 
+#ifdef MOZ_CONTENT_SANDBOX
+class SandboxFilterImplContent : public SandboxFilterImpl {
+protected:
+  virtual void Build() MOZ_OVERRIDE;
+};
+
+void
+SandboxFilterImplContent::Build() {
   /* 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
    * 2) the child will report which system call has been denied by seccomp-bpf,
    *    just before exiting
@@ -324,10 +309,164 @@ SandboxFilterImpl::Build() {
 #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));
 }
+#endif // MOZ_CONTENT_SANDBOX
+
+#ifdef MOZ_GMP_SANDBOX
+class SandboxFilterImplGMP : public SandboxFilterImpl {
+protected:
+  virtual void Build() MOZ_OVERRIDE;
+};
+
+void SandboxFilterImplGMP::Build() {
+  // As for content processes, check the most common syscalls first.
+
+  Allow(SYSCALL_WITH_ARG(clock_gettime, 0, CLOCK_MONOTONIC, CLOCK_REALTIME));
+  Allow(SYSCALL(futex));
+  Allow(SYSCALL(gettimeofday));
+  Allow(SYSCALL(poll));
+  Allow(SYSCALL(write));
+  Allow(SYSCALL(read));
+  Allow(SYSCALL(epoll_wait));
+  Allow(SOCKETCALL(recvmsg, RECVMSG));
+  Allow(SOCKETCALL(sendmsg, SENDMSG));
+  Allow(SYSCALL(time));
+
+  // Nothing after this line is performance-critical.
+
+#if SYSCALL_EXISTS(mmap2)
+  Allow(SYSCALL(mmap2));
+#else
+  Allow(SYSCALL(mmap));
+#endif
+  Allow(SYSCALL_LARGEFILE(fstat, fstat64));
+  Allow(SYSCALL(munmap));
+
+  Allow(SYSCALL(getpid));
+  Allow(SYSCALL(gettid));
+
+  // The glibc source hasn't changed the thread creation clone flags
+  // since 2004, so this *should* be safe to hard-code.  Bionic is
+  // different, but MOZ_GMP_SANDBOX isn't supported there yet.
+  //
+  // At minimum we should require CLONE_THREAD, so that a single
+  // SIGKILL from the parent will destroy all descendant tasks.  In
+  // general, pinning down as much of the flags word as possible is a
+  // good idea, because it exposes a lot of subtle (and probably not
+  // well tested in all cases) kernel functionality.
+  //
+  // WARNING: s390 and cris pass the flags in a different arg -- see
+  // CLONE_BACKWARDS2 in arch/Kconfig in the kernel source -- but we
+  // don't support seccomp-bpf on those archs yet.
+  static const int new_thread_flags = CLONE_VM | CLONE_FS | CLONE_FILES |
+    CLONE_SIGHAND | CLONE_THREAD | CLONE_SYSVSEM | CLONE_SETTLS |
+    CLONE_PARENT_SETTID | CLONE_CHILD_CLEARTID;
+  Allow(SYSCALL_WITH_ARG(clone, 0, new_thread_flags));
+
+  Allow(SYSCALL_WITH_ARG(prctl, 0, PR_GET_SECCOMP, PR_SET_NAME));
+
+#if SYSCALL_EXISTS(set_robust_list)
+  Allow(SYSCALL(set_robust_list));
+#endif
+
+  // NSPR can call this when creating a thread, but it will accept a
+  // polite "no".
+  Deny(EACCES, SYSCALL(getpriority));
+
+  // Stack bounds are obtained via pthread_getattr_np, which calls
+  // this but doesn't actually need it:
+  Deny(ENOSYS, SYSCALL(sched_getaffinity));
+
+#ifdef MOZ_ASAN
+  Allow(SYSCALL(sigaltstack));
+#endif
+
+  Allow(SYSCALL(mprotect));
+  Allow(SYSCALL_WITH_ARG(madvise, 2, MADV_DONTNEED));
+
+#if SYSCALL_EXISTS(sigreturn)
+  Allow(SYSCALL(sigreturn));
+#endif
+  Allow(SYSCALL(rt_sigreturn));
+
+  Allow(SYSCALL(restart_syscall));
+  Allow(SYSCALL(close));
+
+  // "Sleeping for 300 seconds" in debug crashes; possibly other uses.
+  Allow(SYSCALL(nanosleep));
+
+  // For the crash reporter:
+#if SYSCALL_EXISTS(sigprocmask)
+  Allow(SYSCALL(sigprocmask));
+#endif
+  Allow(SYSCALL(rt_sigprocmask));
+#if SYSCALL_EXISTS(sigaction)
+  Allow(SYSCALL(sigaction));
+#endif
+  Allow(SYSCALL(rt_sigaction));
+  Allow(SOCKETCALL(socketpair, SOCKETPAIR));
+  Allow(SYSCALL_WITH_ARG(tgkill, 0, uint32_t(getpid())));
+  Allow(SYSCALL_WITH_ARG(prctl, 0, PR_SET_DUMPABLE));
+
+  // Note for when GMP is supported on an ARM platform: Add whichever
+  // of the ARM-specific syscalls are needed for this type of process.
+
+  Allow(SYSCALL(epoll_ctl));
+  Allow(SYSCALL(exit));
+  Allow(SYSCALL(exit_group));
+}
+#endif // MOZ_GMP_SANDBOX
+
+SandboxFilter::SandboxFilter(const sock_fprog** aStored, SandboxType aType,
+                             bool aVerbose)
+  : mStored(aStored)
+{
+  MOZ_ASSERT(*mStored == nullptr);
+  std::vector<struct sock_filter> filterVec;
+  SandboxFilterImpl *impl;
+
+  switch (aType) {
+  case kSandboxContentProcess:
+#ifdef MOZ_CONTENT_SANDBOX
+    impl = new SandboxFilterImplContent();
+#else
+    MOZ_CRASH("Content process sandboxing not supported in this build!");
+#endif
+    break;
+  case kSandboxMediaPlugin:
+#ifdef MOZ_GMP_SANDBOX
+    impl = new SandboxFilterImplGMP();
+#else
+    MOZ_CRASH("Gecko Media Plugin process sandboxing not supported in this"
+              " build!");
+#endif
+    break;
+  default:
+    MOZ_CRASH("Nonexistent sandbox type!");
+  }
+  impl->Build();
+  impl->Finish();
+  impl->Compile(&filterVec, aVerbose);
+  delete impl;
+
+  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;
+}
 
 }
--- a/security/sandbox/linux/SandboxFilter.h
+++ b/security/sandbox/linux/SandboxFilter.h
@@ -6,22 +6,30 @@
 
 #ifndef mozilla_SandboxFilter_h
 #define mozilla_SandboxFilter_h
 
 struct sock_fprog;
 struct sock_filter;
 
 namespace mozilla {
-  class SandboxFilter {
-    sock_filter *mFilter;
-    sock_fprog *mProg;
-    const sock_fprog **mStored;
-  public:
+
+enum SandboxType {
+  kSandboxContentProcess,
+  kSandboxMediaPlugin
+};
+
+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();
-  };
-}
+  SandboxFilter(const sock_fprog** aStored, SandboxType aBox,
+                bool aVerbose = false);
+  ~SandboxFilter();
+};
+
+} // namespace mozilla
 
 #endif
--- a/toolkit/toolkit.mozbuild
+++ b/toolkit/toolkit.mozbuild
@@ -1,17 +1,17 @@
 # vim: set filetype=python:
 # 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/.
 
 if CONFIG['LIBXUL_SDK']:
     error('toolkit.mozbuild is not compatible with --enable-libxul-sdk=')
 
-if CONFIG['MOZ_CONTENT_SANDBOX'] or (CONFIG['OS_ARCH'] == 'WINNT'):
+if CONFIG['MOZ_CONTENT_SANDBOX'] or CONFIG['MOZ_GMP_SANDBOX']:
     add_tier_dir('sandbox', 'security/sandbox')
 
 # Depends on NSS and NSPR, and must be built after sandbox or else B2G emulator
 # builds fail.
 add_tier_dir('platform', 'security/certverifier')
 
 # Depends on certverifier
 add_tier_dir('platform', 'security/apps')