Merge from Chromium at DEPS revision 278205

This commit was generated by merge_to_master.py.

Change-Id: I23f1e7ea8c154ba72e7fb594436216f861f868ab
diff --git a/sandbox/BUILD.gn b/sandbox/BUILD.gn
index 71de29f..e3a8b62 100644
--- a/sandbox/BUILD.gn
+++ b/sandbox/BUILD.gn
@@ -6,9 +6,8 @@
 group("sandbox") {
   if (is_win) {
     deps = [ "//sandbox/win:sandbox" ]
-  # TODO(GYP)
-  #} else if (is_mac) {
-  #  deps = [ "//sandbox/mac:sandbox" ]
+  } else if (is_mac) {
+    deps = [ "//sandbox/mac:sandbox" ]
   } else if (is_linux || is_android) {
     deps = [ "//sandbox/linux:sandbox" ]
   }
diff --git a/sandbox/linux/sandbox_linux.gypi b/sandbox/linux/sandbox_linux.gypi
index 53518b8..6235248 100644
--- a/sandbox/linux/sandbox_linux.gypi
+++ b/sandbox/linux/sandbox_linux.gypi
@@ -216,6 +216,13 @@
       'include_dirs': [
         '../..',
       ],
+      # Do not use any sanitizer tools with this binary. http://crbug.com/382766
+      'cflags/': [
+        ['exclude', '-fsanitize'],
+      ],
+      'ldflags/': [
+        ['exclude', '-fsanitize'],
+      ],
     },
     { 'target_name': 'sandbox_services',
       'type': '<(component)',
diff --git a/sandbox/linux/seccomp-bpf/codegen.cc b/sandbox/linux/seccomp-bpf/codegen.cc
index 211e659..c90bffc 100644
--- a/sandbox/linux/seccomp-bpf/codegen.cc
+++ b/sandbox/linux/seccomp-bpf/codegen.cc
@@ -106,6 +106,8 @@
           fprintf(stderr, "Trap #%d\n", iter->k & SECCOMP_RET_DATA);
         } else if ((iter->k & SECCOMP_RET_ACTION) == SECCOMP_RET_ERRNO) {
           fprintf(stderr, "errno = %d\n", iter->k & SECCOMP_RET_DATA);
+        } else if ((iter->k & SECCOMP_RET_ACTION) == SECCOMP_RET_TRACE) {
+          fprintf(stderr, "Trace #%d\n", iter->k & SECCOMP_RET_DATA);
         } else if (iter->k == SECCOMP_RET_ALLOW) {
           fprintf(stderr, "Allowed\n");
         } else {
diff --git a/sandbox/linux/seccomp-bpf/die.cc b/sandbox/linux/seccomp-bpf/die.cc
index 533e2e9..e5bc7c9 100644
--- a/sandbox/linux/seccomp-bpf/die.cc
+++ b/sandbox/linux/seccomp-bpf/die.cc
@@ -22,7 +22,7 @@
   // Especially, since we are dealing with system call filters. Continuing
   // execution would be very bad in most cases where ExitGroup() gets called.
   // So, we'll try a few other strategies too.
-  SandboxSyscall(__NR_exit_group, 1);
+  Syscall::Call(__NR_exit_group, 1);
 
   // We have no idea what our run-time environment looks like. So, signal
   // handlers might or might not do the right thing. Try to reset settings
@@ -30,7 +30,7 @@
   // succeeded in doing so. Nonetheless, triggering a fatal signal could help
   // us terminate.
   signal(SIGSEGV, SIG_DFL);
-  SandboxSyscall(__NR_prctl, PR_SET_DUMPABLE, (void*)0, (void*)0, (void*)0);
+  Syscall::Call(__NR_prctl, PR_SET_DUMPABLE, (void*)0, (void*)0, (void*)0);
   if (*(volatile char*)0) {
   }
 
@@ -40,7 +40,7 @@
   // We in fact retry the system call inside of our loop so that it will
   // stand out when somebody tries to diagnose the problem by using "strace".
   for (;;) {
-    SandboxSyscall(__NR_exit_group, 1);
+    Syscall::Call(__NR_exit_group, 1);
   }
 }
 
@@ -75,7 +75,7 @@
     // No need to loop. Short write()s are unlikely and if they happen we
     // probably prefer them over a loop that blocks.
     ignore_result(
-        HANDLE_EINTR(SandboxSyscall(__NR_write, 2, s.c_str(), s.length())));
+        HANDLE_EINTR(Syscall::Call(__NR_write, 2, s.c_str(), s.length())));
   }
 }
 
diff --git a/sandbox/linux/seccomp-bpf/errorcode.cc b/sandbox/linux/seccomp-bpf/errorcode.cc
index 6484852..5a45e4c 100644
--- a/sandbox/linux/seccomp-bpf/errorcode.cc
+++ b/sandbox/linux/seccomp-bpf/errorcode.cc
@@ -18,6 +18,11 @@
       error_type_ = ET_SIMPLE;
       break;
     default:
+      if ((err & ~SECCOMP_RET_DATA) == ERR_TRACE) {
+        err_ = SECCOMP_RET_TRACE + (err & SECCOMP_RET_DATA);
+        error_type_ = ET_SIMPLE;
+        break;
+      }
       SANDBOX_DIE("Invalid use of ErrorCode object");
   }
 }
diff --git a/sandbox/linux/seccomp-bpf/errorcode.h b/sandbox/linux/seccomp-bpf/errorcode.h
index 04f22ae..2e51381 100644
--- a/sandbox/linux/seccomp-bpf/errorcode.h
+++ b/sandbox/linux/seccomp-bpf/errorcode.h
@@ -30,6 +30,12 @@
     // "errno" (see below) value instead.
     ERR_ALLOWED = 0x04000000,
 
+    // If the progress is being ptraced with PTRACE_O_TRACESECCOMP, then the
+    // tracer will be notified of a PTRACE_EVENT_SECCOMP and allowed to change
+    // or skip the system call.  The lower 16 bits of err will be available to
+    // the tracer via PTRACE_GETEVENTMSG.
+    ERR_TRACE   = 0x08000000,
+
     // Deny the system call with a particular "errno" value.
     // N.B.: It is also possible to return "0" here. That would normally
     //       indicate success, but it won't actually run the system call.
diff --git a/sandbox/linux/seccomp-bpf/errorcode_unittest.cc b/sandbox/linux/seccomp-bpf/errorcode_unittest.cc
index ef04a5f..f3b7748 100644
--- a/sandbox/linux/seccomp-bpf/errorcode_unittest.cc
+++ b/sandbox/linux/seccomp-bpf/errorcode_unittest.cc
@@ -24,6 +24,17 @@
   SandboxBPF sandbox;
   ErrorCode e3 = sandbox.Trap(NULL, NULL);
   SANDBOX_ASSERT((e3.err() & SECCOMP_RET_ACTION)  == SECCOMP_RET_TRAP);
+
+  uint16_t data = 0xdead;
+  ErrorCode e4(ErrorCode::ERR_TRACE + data);
+  SANDBOX_ASSERT(e4.err() == SECCOMP_RET_TRACE + data);
+}
+
+SANDBOX_DEATH_TEST(ErrorCode,
+                   InvalidSeccompRetTrace,
+                   DEATH_MESSAGE("Invalid use of ErrorCode object")) {
+  // Should die if the trace data does not fit in 16 bits.
+  ErrorCode e(ErrorCode::ERR_TRACE + (1 << 16));
 }
 
 SANDBOX_TEST(ErrorCode, Trap) {
diff --git a/sandbox/linux/seccomp-bpf/linux_seccomp.h b/sandbox/linux/seccomp-bpf/linux_seccomp.h
index 0de0259..270e11c 100644
--- a/sandbox/linux/seccomp-bpf/linux_seccomp.h
+++ b/sandbox/linux/seccomp-bpf/linux_seccomp.h
@@ -16,6 +16,14 @@
 #include <asm/unistd.h>
 #include <linux/filter.h>
 
+#include <sys/cdefs.h>
+// Old Bionic versions do not have sys/user.h.  The if can be removed once we no
+// longer need to support these old Bionic versions.
+// All x86_64 builds use a new enough bionic to have sys/user.h.
+#if !defined(__BIONIC__) || defined(__x86_64__)
+#include <sys/user.h>
+#endif
+
 // For audit.h
 #ifndef EM_ARM
 #define EM_ARM    40
@@ -124,6 +132,44 @@
 #define SECCOMP_ARG_LSB_IDX(nr) (offsetof(struct arch_seccomp_data, args) +   \
                                  8*(nr) + 0)
 
+
+#if defined(__BIONIC__)
+// Old Bionic versions don't have sys/user.h, so we just define regs_struct
+// directly.  This can be removed once we no longer need to support these old
+// Bionic versions.
+struct regs_struct {
+  long int ebx;
+  long int ecx;
+  long int edx;
+  long int esi;
+  long int edi;
+  long int ebp;
+  long int eax;
+  long int xds;
+  long int xes;
+  long int xfs;
+  long int xgs;
+  long int orig_eax;
+  long int eip;
+  long int xcs;
+  long int eflags;
+  long int esp;
+  long int xss;
+};
+#else
+typedef user_regs_struct regs_struct;
+#endif
+
+#define SECCOMP_PT_RESULT(_regs)  (_regs).eax
+#define SECCOMP_PT_SYSCALL(_regs) (_regs).orig_eax
+#define SECCOMP_PT_IP(_regs)      (_regs).eip
+#define SECCOMP_PT_PARM1(_regs)   (_regs).ebx
+#define SECCOMP_PT_PARM2(_regs)   (_regs).ecx
+#define SECCOMP_PT_PARM3(_regs)   (_regs).edx
+#define SECCOMP_PT_PARM4(_regs)   (_regs).esi
+#define SECCOMP_PT_PARM5(_regs)   (_regs).edi
+#define SECCOMP_PT_PARM6(_regs)   (_regs).ebp
+
 #elif defined(__x86_64__)
 #define MIN_SYSCALL         0u
 #define MAX_PUBLIC_SYSCALL  1024u
@@ -151,6 +197,17 @@
 #define SECCOMP_ARG_LSB_IDX(nr) (offsetof(struct arch_seccomp_data, args) +   \
                                  8*(nr) + 0)
 
+typedef user_regs_struct regs_struct;
+#define SECCOMP_PT_RESULT(_regs)  (_regs).rax
+#define SECCOMP_PT_SYSCALL(_regs) (_regs).orig_rax
+#define SECCOMP_PT_IP(_regs)      (_regs).rip
+#define SECCOMP_PT_PARM1(_regs)   (_regs).rdi
+#define SECCOMP_PT_PARM2(_regs)   (_regs).rsi
+#define SECCOMP_PT_PARM3(_regs)   (_regs).rdx
+#define SECCOMP_PT_PARM4(_regs)   (_regs).r10
+#define SECCOMP_PT_PARM5(_regs)   (_regs).r8
+#define SECCOMP_PT_PARM6(_regs)   (_regs).r9
+
 #elif defined(__arm__) && (defined(__thumb__) || defined(__ARM_EABI__))
 // ARM EABI includes "ARM private" system calls starting at |__ARM_NR_BASE|,
 // and a "ghost syscall private to the kernel", cmpxchg,
@@ -189,6 +246,46 @@
 #define SECCOMP_ARG_LSB_IDX(nr) (offsetof(struct arch_seccomp_data, args) +   \
                                  8*(nr) + 0)
 
+#if defined(__BIONIC__)
+// Old Bionic versions don't have sys/user.h, so we just define regs_struct
+// directly.  This can be removed once we no longer need to support these old
+// Bionic versions.
+struct regs_struct {
+  unsigned long uregs[18];
+};
+#else
+typedef user_regs regs_struct;
+#endif
+
+#define REG_cpsr    uregs[16]
+#define REG_pc      uregs[15]
+#define REG_lr      uregs[14]
+#define REG_sp      uregs[13]
+#define REG_ip      uregs[12]
+#define REG_fp      uregs[11]
+#define REG_r10     uregs[10]
+#define REG_r9      uregs[9]
+#define REG_r8      uregs[8]
+#define REG_r7      uregs[7]
+#define REG_r6      uregs[6]
+#define REG_r5      uregs[5]
+#define REG_r4      uregs[4]
+#define REG_r3      uregs[3]
+#define REG_r2      uregs[2]
+#define REG_r1      uregs[1]
+#define REG_r0      uregs[0]
+#define REG_ORIG_r0 uregs[17]
+
+#define SECCOMP_PT_RESULT(_regs)  (_regs).REG_r0
+#define SECCOMP_PT_SYSCALL(_regs) (_regs).REG_r7
+#define SECCOMP_PT_IP(_regs)      (_regs).REG_pc
+#define SECCOMP_PT_PARM1(_regs)   (_regs).REG_r0
+#define SECCOMP_PT_PARM2(_regs)   (_regs).REG_r1
+#define SECCOMP_PT_PARM3(_regs)   (_regs).REG_r2
+#define SECCOMP_PT_PARM4(_regs)   (_regs).REG_r3
+#define SECCOMP_PT_PARM5(_regs)   (_regs).REG_r4
+#define SECCOMP_PT_PARM6(_regs)   (_regs).REG_r5
+
 #else
 #error Unsupported target platform
 
diff --git a/sandbox/linux/seccomp-bpf/sandbox_bpf.cc b/sandbox/linux/seccomp-bpf/sandbox_bpf.cc
index c5c6f61..6ecbca9 100644
--- a/sandbox/linux/seccomp-bpf/sandbox_bpf.cc
+++ b/sandbox/linux/seccomp-bpf/sandbox_bpf.cc
@@ -613,7 +613,7 @@
     // and of course, we make sure to only ever enable this feature if it
     // is actually requested by the sandbox policy.
     if (has_unsafe_traps) {
-      if (SandboxSyscall(-1) == -1 && errno == ENOSYS) {
+      if (Syscall::Call(-1) == -1 && errno == ENOSYS) {
         SANDBOX_DIE(
             "Support for UnsafeTrap() has not yet been ported to this "
             "architecture");
@@ -650,9 +650,8 @@
       gen->Traverse(jumptable, RedirectToUserspace, this);
 
       // Allow system calls, if they originate from our magic return address
-      // (which we can query by calling SandboxSyscall(-1)).
-      uintptr_t syscall_entry_point =
-          static_cast<uintptr_t>(SandboxSyscall(-1));
+      // (which we can query by calling Syscall::Call(-1)).
+      uintptr_t syscall_entry_point = static_cast<uintptr_t>(Syscall::Call(-1));
       uint32_t low = static_cast<uint32_t>(syscall_entry_point);
 #if __SIZEOF_POINTER__ > 4
       uint32_t hi = static_cast<uint32_t>(syscall_entry_point >> 32);
@@ -1003,13 +1002,13 @@
 }
 
 intptr_t SandboxBPF::ForwardSyscall(const struct arch_seccomp_data& args) {
-  return SandboxSyscall(args.nr,
-                        static_cast<intptr_t>(args.args[0]),
-                        static_cast<intptr_t>(args.args[1]),
-                        static_cast<intptr_t>(args.args[2]),
-                        static_cast<intptr_t>(args.args[3]),
-                        static_cast<intptr_t>(args.args[4]),
-                        static_cast<intptr_t>(args.args[5]));
+  return Syscall::Call(args.nr,
+                       static_cast<intptr_t>(args.args[0]),
+                       static_cast<intptr_t>(args.args[1]),
+                       static_cast<intptr_t>(args.args[2]),
+                       static_cast<intptr_t>(args.args[3]),
+                       static_cast<intptr_t>(args.args[4]),
+                       static_cast<intptr_t>(args.args[5]));
 }
 
 ErrorCode SandboxBPF::Cond(int argno,
diff --git a/sandbox/linux/seccomp-bpf/sandbox_bpf.h b/sandbox/linux/seccomp-bpf/sandbox_bpf.h
index 9bb414a..32fe2a7 100644
--- a/sandbox/linux/seccomp-bpf/sandbox_bpf.h
+++ b/sandbox/linux/seccomp-bpf/sandbox_bpf.h
@@ -25,6 +25,7 @@
 
 namespace sandbox {
 
+// This must match the kernel's seccomp_data structure.
 struct arch_seccomp_data {
   int nr;
   uint32_t arch;
diff --git a/sandbox/linux/seccomp-bpf/sandbox_bpf_unittest.cc b/sandbox/linux/seccomp-bpf/sandbox_bpf_unittest.cc
index 0341d2f..06ba209 100644
--- a/sandbox/linux/seccomp-bpf/sandbox_bpf_unittest.cc
+++ b/sandbox/linux/seccomp-bpf/sandbox_bpf_unittest.cc
@@ -5,7 +5,9 @@
 #include <errno.h>
 #include <pthread.h>
 #include <sched.h>
+#include <signal.h>
 #include <sys/prctl.h>
+#include <sys/ptrace.h>
 #include <sys/syscall.h>
 #include <sys/time.h>
 #include <sys/types.h>
@@ -24,6 +26,7 @@
 #include "base/logging.h"
 #include "base/macros.h"
 #include "base/memory/scoped_ptr.h"
+#include "base/posix/eintr_wrapper.h"
 #include "build/build_config.h"
 #include "sandbox/linux/seccomp-bpf/bpf_tests.h"
 #include "sandbox/linux/seccomp-bpf/syscall.h"
@@ -1201,7 +1204,7 @@
     // based on the system call number and the parameters that we decided
     // to pass in. Verify that this condition holds true.
     BPF_ASSERT(
-        SandboxSyscall(
+        Syscall::Call(
             sysno, args[0], args[1], args[2], args[3], args[4], args[5]) ==
         -err);
   }
@@ -1276,18 +1279,18 @@
 }
 
 BPF_TEST_C(SandboxBPF, EqualityArgumentWidth, EqualityArgumentWidthPolicy) {
-  BPF_ASSERT(SandboxSyscall(__NR_uname, 0, 0x55555555) == -1);
-  BPF_ASSERT(SandboxSyscall(__NR_uname, 0, 0xAAAAAAAA) == -2);
+  BPF_ASSERT(Syscall::Call(__NR_uname, 0, 0x55555555) == -1);
+  BPF_ASSERT(Syscall::Call(__NR_uname, 0, 0xAAAAAAAA) == -2);
 #if __SIZEOF_POINTER__ > 4
   // On 32bit machines, there is no way to pass a 64bit argument through the
   // syscall interface. So, we have to skip the part of the test that requires
   // 64bit arguments.
-  BPF_ASSERT(SandboxSyscall(__NR_uname, 1, 0x55555555AAAAAAAAULL) == -1);
-  BPF_ASSERT(SandboxSyscall(__NR_uname, 1, 0x5555555500000000ULL) == -2);
-  BPF_ASSERT(SandboxSyscall(__NR_uname, 1, 0x5555555511111111ULL) == -2);
-  BPF_ASSERT(SandboxSyscall(__NR_uname, 1, 0x11111111AAAAAAAAULL) == -2);
+  BPF_ASSERT(Syscall::Call(__NR_uname, 1, 0x55555555AAAAAAAAULL) == -1);
+  BPF_ASSERT(Syscall::Call(__NR_uname, 1, 0x5555555500000000ULL) == -2);
+  BPF_ASSERT(Syscall::Call(__NR_uname, 1, 0x5555555511111111ULL) == -2);
+  BPF_ASSERT(Syscall::Call(__NR_uname, 1, 0x11111111AAAAAAAAULL) == -2);
 #else
-  BPF_ASSERT(SandboxSyscall(__NR_uname, 1, 0x55555555) == -2);
+  BPF_ASSERT(Syscall::Call(__NR_uname, 1, 0x55555555) == -2);
 #endif
 }
 
@@ -1299,7 +1302,7 @@
                  EqualityArgumentUnallowed64bit,
                  DEATH_MESSAGE("Unexpected 64bit argument detected"),
                  EqualityArgumentWidthPolicy) {
-  SandboxSyscall(__NR_uname, 0, 0x5555555555555555ULL);
+  Syscall::Call(__NR_uname, 0, 0x5555555555555555ULL);
 }
 #endif
 
@@ -1327,9 +1330,9 @@
 BPF_TEST_C(SandboxBPF,
            EqualityWithNegativeArguments,
            EqualityWithNegativeArgumentsPolicy) {
-  BPF_ASSERT(SandboxSyscall(__NR_uname, 0xFFFFFFFF) == -1);
-  BPF_ASSERT(SandboxSyscall(__NR_uname, -1) == -1);
-  BPF_ASSERT(SandboxSyscall(__NR_uname, -1LL) == -1);
+  BPF_ASSERT(Syscall::Call(__NR_uname, 0xFFFFFFFF) == -1);
+  BPF_ASSERT(Syscall::Call(__NR_uname, -1) == -1);
+  BPF_ASSERT(Syscall::Call(__NR_uname, -1LL) == -1);
 }
 
 #if __SIZEOF_POINTER__ > 4
@@ -1340,7 +1343,7 @@
   // When expecting a 32bit system call argument, we look at the MSB of the
   // 64bit value and allow both "0" and "-1". But the latter is allowed only
   // iff the LSB was negative. So, this death test should error out.
-  BPF_ASSERT(SandboxSyscall(__NR_uname, 0xFFFFFFFF00000000LL) == -1);
+  BPF_ASSERT(Syscall::Call(__NR_uname, 0xFFFFFFFF00000000LL) == -1);
 }
 #endif
 class AllBitTestPolicy : public SandboxBPFPolicy {
@@ -1430,10 +1433,10 @@
 //       to make changes to these values, you will have to edit the
 //       test policy instead.
 #define BITMASK_TEST(testcase, arg, op, mask, expected_value) \
-  BPF_ASSERT(SandboxSyscall(__NR_uname, (testcase), (arg)) == (expected_value))
+  BPF_ASSERT(Syscall::Call(__NR_uname, (testcase), (arg)) == (expected_value))
 
 // Our uname() system call returns ErrorCode(1) for success and
-// ErrorCode(0) for failure. SandboxSyscall() turns this into an
+// ErrorCode(0) for failure. Syscall::Call() turns this into an
 // exit code of -1 or 0.
 #define EXPECT_FAILURE 0
 #define EXPECT_SUCCESS -1
@@ -1863,7 +1866,7 @@
 
 static void* ThreadFnc(void* arg) {
   ++*reinterpret_cast<int*>(arg);
-  SandboxSyscall(__NR_futex, arg, FUTEX_WAKE, 1, 0, 0, 0);
+  Syscall::Call(__NR_futex, arg, FUTEX_WAKE, 1, 0, 0, 0);
   return NULL;
 }
 
@@ -1882,7 +1885,7 @@
   BPF_ASSERT(!pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED));
   BPF_ASSERT(!pthread_create(&thread, &attr, ThreadFnc, &thread_ran));
   BPF_ASSERT(!pthread_attr_destroy(&attr));
-  while (SandboxSyscall(__NR_futex, &thread_ran, FUTEX_WAIT, 0, 0, 0, 0) ==
+  while (Syscall::Call(__NR_futex, &thread_ran, FUTEX_WAIT, 0, 0, 0, 0) ==
          -EINTR) {
   }
   BPF_ASSERT(thread_ran);
@@ -1893,11 +1896,11 @@
   // run-time libraries other than glibc might call __NR_fork instead of
   // __NR_clone, and that would introduce a bogus test failure.
   int pid;
-  BPF_ASSERT(SandboxSyscall(__NR_clone,
-                            CLONE_CHILD_CLEARTID | CLONE_CHILD_SETTID | SIGCHLD,
-                            0,
-                            0,
-                            &pid) == -EPERM);
+  BPF_ASSERT(Syscall::Call(__NR_clone,
+                           CLONE_CHILD_CLEARTID | CLONE_CHILD_SETTID | SIGCHLD,
+                           0,
+                           0,
+                           &pid) == -EPERM);
 }
 
 BPF_TEST_C(SandboxBPF, PthreadEquality, PthreadPolicyEquality) {
@@ -1908,6 +1911,154 @@
   PthreadTest();
 }
 
+// libc might not define these even though the kernel supports it.
+#ifndef PTRACE_O_TRACESECCOMP
+#define PTRACE_O_TRACESECCOMP 0x00000080
+#endif
+
+#ifdef PTRACE_EVENT_SECCOMP
+#define IS_SECCOMP_EVENT(status) ((status >> 16) == PTRACE_EVENT_SECCOMP)
+#else
+// When Debian/Ubuntu backported seccomp-bpf support into earlier kernels, they
+// changed the value of PTRACE_EVENT_SECCOMP from 7 to 8, since 7 was taken by
+// PTRACE_EVENT_STOP (upstream chose to renumber PTRACE_EVENT_STOP to 128).  If
+// PTRACE_EVENT_SECCOMP isn't defined, we have no choice but to consider both
+// values here.
+#define IS_SECCOMP_EVENT(status) ((status >> 16) == 7 || (status >> 16) == 8)
+#endif
+
+#if defined(__arm__)
+#ifndef PTRACE_SET_SYSCALL
+#define PTRACE_SET_SYSCALL 23
+#endif
+#endif
+
+// Changes the syscall to run for a child being sandboxed using seccomp-bpf with
+// PTRACE_O_TRACESECCOMP.  Should only be called when the child is stopped on
+// PTRACE_EVENT_SECCOMP.
+//
+// regs should contain the current set of registers of the child, obtained using
+// PTRACE_GETREGS.
+//
+// Depending on the architecture, this may modify regs, so the caller is
+// responsible for committing these changes using PTRACE_SETREGS.
+long SetSyscall(pid_t pid, regs_struct* regs, int syscall_number) {
+#if defined(__arm__)
+  // On ARM, the syscall is changed using PTRACE_SET_SYSCALL.  We cannot use the
+  // libc ptrace call as the request parameter is an enum, and
+  // PTRACE_SET_SYSCALL may not be in the enum.
+  return syscall(__NR_ptrace, PTRACE_SET_SYSCALL, pid, NULL, syscall_number);
+#endif
+
+  SECCOMP_PT_SYSCALL(*regs) = syscall_number;
+  return 0;
+}
+
+const uint16_t kTraceData = 0xcc;
+
+class TraceAllPolicy : public SandboxBPFPolicy {
+ public:
+  TraceAllPolicy() {}
+  virtual ~TraceAllPolicy() {}
+
+  virtual ErrorCode EvaluateSyscall(SandboxBPF* sandbox_compiler,
+                                    int system_call_number) const OVERRIDE {
+    return ErrorCode(ErrorCode::ERR_TRACE + kTraceData);
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(TraceAllPolicy);
+};
+
+SANDBOX_TEST(SandboxBPF, DISABLE_ON_TSAN(SeccompRetTrace)) {
+  if (SandboxBPF::SupportsSeccompSandbox(-1) !=
+      sandbox::SandboxBPF::STATUS_AVAILABLE) {
+    return;
+  }
+
+#if defined(__arm__)
+  printf("This test is currently disabled on ARM due to a kernel bug.");
+  return;
+#endif
+
+  pid_t pid = fork();
+  BPF_ASSERT_NE(-1, pid);
+  if (pid == 0) {
+    pid_t my_pid = getpid();
+    BPF_ASSERT_NE(-1, ptrace(PTRACE_TRACEME, -1, NULL, NULL));
+    BPF_ASSERT_EQ(0, raise(SIGSTOP));
+    SandboxBPF sandbox;
+    sandbox.SetSandboxPolicy(new TraceAllPolicy);
+    BPF_ASSERT(sandbox.StartSandbox(SandboxBPF::PROCESS_SINGLE_THREADED));
+
+    // getpid is allowed.
+    BPF_ASSERT_EQ(my_pid, syscall(__NR_getpid));
+
+    // write to stdout is skipped and returns a fake value.
+    BPF_ASSERT_EQ(kExpectedReturnValue,
+                  syscall(__NR_write, STDOUT_FILENO, "A", 1));
+
+    // kill is rewritten to exit(kExpectedReturnValue).
+    syscall(__NR_kill, my_pid, SIGKILL);
+
+    // Should not be reached.
+    BPF_ASSERT(false);
+  }
+
+  int status;
+  BPF_ASSERT(HANDLE_EINTR(waitpid(pid, &status, WUNTRACED)) != -1);
+  BPF_ASSERT(WIFSTOPPED(status));
+
+  BPF_ASSERT_NE(-1, ptrace(PTRACE_SETOPTIONS, pid, NULL,
+                           reinterpret_cast<void*>(PTRACE_O_TRACESECCOMP)));
+  BPF_ASSERT_NE(-1, ptrace(PTRACE_CONT, pid, NULL, NULL));
+  while (true) {
+    BPF_ASSERT(HANDLE_EINTR(waitpid(pid, &status, 0)) != -1);
+    if (WIFEXITED(status) || WIFSIGNALED(status)) {
+      BPF_ASSERT(WIFEXITED(status));
+      BPF_ASSERT_EQ(kExpectedReturnValue, WEXITSTATUS(status));
+      break;
+    }
+
+    if (!WIFSTOPPED(status) || WSTOPSIG(status) != SIGTRAP ||
+        !IS_SECCOMP_EVENT(status)) {
+      BPF_ASSERT_NE(-1, ptrace(PTRACE_CONT, pid, NULL, NULL));
+      continue;
+    }
+
+    unsigned long data;
+    BPF_ASSERT_NE(-1, ptrace(PTRACE_GETEVENTMSG, pid, NULL, &data));
+    BPF_ASSERT_EQ(kTraceData, data);
+
+    regs_struct regs;
+    BPF_ASSERT_NE(-1, ptrace(PTRACE_GETREGS, pid, NULL, &regs));
+    switch (SECCOMP_PT_SYSCALL(regs)) {
+      case __NR_write:
+        // Skip writes to stdout, make it return kExpectedReturnValue.  Allow
+        // writes to stderr so that BPF_ASSERT messages show up.
+        if (SECCOMP_PT_PARM1(regs) == STDOUT_FILENO) {
+          BPF_ASSERT_NE(-1, SetSyscall(pid, &regs, -1));
+          SECCOMP_PT_RESULT(regs) = kExpectedReturnValue;
+          BPF_ASSERT_NE(-1, ptrace(PTRACE_SETREGS, pid, NULL, &regs));
+        }
+        break;
+
+      case __NR_kill:
+        // Rewrite to exit(kExpectedReturnValue).
+        BPF_ASSERT_NE(-1, SetSyscall(pid, &regs, __NR_exit));
+        SECCOMP_PT_PARM1(regs) = kExpectedReturnValue;
+        BPF_ASSERT_NE(-1, ptrace(PTRACE_SETREGS, pid, NULL, &regs));
+        break;
+
+      default:
+        // Allow all other syscalls.
+        break;
+    }
+
+    BPF_ASSERT_NE(-1, ptrace(PTRACE_CONT, pid, NULL, NULL));
+  }
+}
+
 }  // namespace
 
 }  // namespace sandbox
diff --git a/sandbox/linux/seccomp-bpf/syscall.cc b/sandbox/linux/seccomp-bpf/syscall.cc
index fd599e8..64c0b8e 100644
--- a/sandbox/linux/seccomp-bpf/syscall.cc
+++ b/sandbox/linux/seccomp-bpf/syscall.cc
@@ -11,169 +11,177 @@
 
 namespace sandbox {
 
-  asm(      // We need to be able to tell the kernel exactly where we made a
-            // system call. The C++ compiler likes to sometimes clone or
-            // inline code, which would inadvertently end up duplicating
-            // the entry point.
-            // "gcc" can suppress code duplication with suitable function
-            // attributes, but "clang" doesn't have this ability.
-            // The "clang" developer mailing list suggested that the correct
-            // and portable solution is a file-scope assembly block.
-            // N.B. We do mark our code as a proper function so that backtraces
-            // work correctly. But we make absolutely no attempt to use the
-            // ABI's calling conventions for passing arguments. We will only
-            // ever be called from assembly code and thus can pick more
-            // suitable calling conventions.
-#if defined(__i386__)
-            ".text\n"
-            ".align 16, 0x90\n"
-            ".type SyscallAsm, @function\n"
- "SyscallAsm:.cfi_startproc\n"
-            // Check if "%eax" is negative. If so, do not attempt to make a
-            // system call. Instead, compute the return address that is visible
-            // to the kernel after we execute "int $0x80". This address can be
-            // used as a marker that BPF code inspects.
-            "test %eax, %eax\n"
-            "jge  1f\n"
-            // Always, make sure that our code is position-independent, or
-            // address space randomization might not work on i386. This means,
-            // we can't use "lea", but instead have to rely on "call/pop".
-            "call 0f;   .cfi_adjust_cfa_offset  4\n"
-          "0:pop  %eax; .cfi_adjust_cfa_offset -4\n"
-            "addl $2f-0b, %eax\n"
-            "ret\n"
-            // Save register that we don't want to clobber. On i386, we need to
-            // save relatively aggressively, as there are a couple or registers
-            // that are used internally (e.g. %ebx for position-independent
-            // code, and %ebp for the frame pointer), and as we need to keep at
-            // least a few registers available for the register allocator.
-          "1:push %esi; .cfi_adjust_cfa_offset 4\n"
-            "push %edi; .cfi_adjust_cfa_offset 4\n"
-            "push %ebx; .cfi_adjust_cfa_offset 4\n"
-            "push %ebp; .cfi_adjust_cfa_offset 4\n"
-            // Copy entries from the array holding the arguments into the
-            // correct CPU registers.
-            "movl  0(%edi), %ebx\n"
-            "movl  4(%edi), %ecx\n"
-            "movl  8(%edi), %edx\n"
-            "movl 12(%edi), %esi\n"
-            "movl 20(%edi), %ebp\n"
-            "movl 16(%edi), %edi\n"
-            // Enter the kernel.
-            "int  $0x80\n"
-            // This is our "magic" return address that the BPF filter sees.
-          "2:"
-            // Restore any clobbered registers that we didn't declare to the
-            // compiler.
-            "pop  %ebp; .cfi_adjust_cfa_offset -4\n"
-            "pop  %ebx; .cfi_adjust_cfa_offset -4\n"
-            "pop  %edi; .cfi_adjust_cfa_offset -4\n"
-            "pop  %esi; .cfi_adjust_cfa_offset -4\n"
-            "ret\n"
-            ".cfi_endproc\n"
-          "9:.size SyscallAsm, 9b-SyscallAsm\n"
-#elif defined(__x86_64__)
-            ".text\n"
-            ".align 16, 0x90\n"
-            ".type SyscallAsm, @function\n"
- "SyscallAsm:.cfi_startproc\n"
-            // Check if "%rax" is negative. If so, do not attempt to make a
-            // system call. Instead, compute the return address that is visible
-            // to the kernel after we execute "syscall". This address can be
-            // used as a marker that BPF code inspects.
-            "test %rax, %rax\n"
-            "jge  1f\n"
-            // Always make sure that our code is position-independent, or the
-            // linker will throw a hissy fit on x86-64.
-            "call 0f;   .cfi_adjust_cfa_offset  8\n"
-          "0:pop  %rax; .cfi_adjust_cfa_offset -8\n"
-            "addq $2f-0b, %rax\n"
-            "ret\n"
-            // We declared all clobbered registers to the compiler. On x86-64,
-            // there really isn't much of a problem with register pressure. So,
-            // we can go ahead and directly copy the entries from the arguments
-            // array into the appropriate CPU registers.
-          "1:movq  0(%r12), %rdi\n"
-            "movq  8(%r12), %rsi\n"
-            "movq 16(%r12), %rdx\n"
-            "movq 24(%r12), %r10\n"
-            "movq 32(%r12), %r8\n"
-            "movq 40(%r12), %r9\n"
-            // Enter the kernel.
-            "syscall\n"
-            // This is our "magic" return address that the BPF filter sees.
-          "2:ret\n"
-            ".cfi_endproc\n"
-          "9:.size SyscallAsm, 9b-SyscallAsm\n"
-#elif defined(__arm__)
-            // Throughout this file, we use the same mode (ARM vs. thumb)
-            // that the C++ compiler uses. This means, when transfering control
-            // from C++ to assembly code, we do not need to switch modes (e.g.
-            // by using the "bx" instruction). It also means that our assembly
-            // code should not be invoked directly from code that lives in
-            // other compilation units, as we don't bother implementing thumb
-            // interworking. That's OK, as we don't make any of the assembly
-            // symbols public. They are all local to this file.
-            ".text\n"
-            ".align 2\n"
-            ".type SyscallAsm, %function\n"
-#if defined(__thumb__)
-            ".thumb_func\n"
-#else
-            ".arm\n"
-#endif
- "SyscallAsm:.fnstart\n"
-            "@ args = 0, pretend = 0, frame = 8\n"
-            "@ frame_needed = 1, uses_anonymous_args = 0\n"
-#if defined(__thumb__)
-            ".cfi_startproc\n"
-            "push {r7, lr}\n"
-            ".cfi_offset 14, -4\n"
-            ".cfi_offset  7, -8\n"
-            "mov r7, sp\n"
-            ".cfi_def_cfa_register 7\n"
-            ".cfi_def_cfa_offset 8\n"
-#else
-            "stmfd sp!, {fp, lr}\n"
-            "add fp, sp, #4\n"
-#endif
-            // Check if "r0" is negative. If so, do not attempt to make a
-            // system call. Instead, compute the return address that is visible
-            // to the kernel after we execute "swi 0". This address can be
-            // used as a marker that BPF code inspects.
-            "cmp r0, #0\n"
-            "bge 1f\n"
-            "adr r0, 2f\n"
-            "b   2f\n"
-            // We declared (almost) all clobbered registers to the compiler. On
-            // ARM there is no particular register pressure. So, we can go
-            // ahead and directly copy the entries from the arguments array
-            // into the appropriate CPU registers.
-          "1:ldr r5, [r6, #20]\n"
-            "ldr r4, [r6, #16]\n"
-            "ldr r3, [r6, #12]\n"
-            "ldr r2, [r6, #8]\n"
-            "ldr r1, [r6, #4]\n"
-            "mov r7, r0\n"
-            "ldr r0, [r6, #0]\n"
-            // Enter the kernel
-            "swi 0\n"
-            // Restore the frame pointer. Also restore the program counter from
-            // the link register; this makes us return to the caller.
-#if defined(__thumb__)
-          "2:pop {r7, pc}\n"
-            ".cfi_endproc\n"
-#else
-          "2:ldmfd sp!, {fp, pc}\n"
-#endif
-            ".fnend\n"
-          "9:.size SyscallAsm, 9b-SyscallAsm\n"
-#endif
-  );  // asm
+namespace {
 
-intptr_t SandboxSyscall(int nr,
-                        intptr_t p0, intptr_t p1, intptr_t p2,
-                        intptr_t p3, intptr_t p4, intptr_t p5) {
+asm(// We need to be able to tell the kernel exactly where we made a
+    // system call. The C++ compiler likes to sometimes clone or
+    // inline code, which would inadvertently end up duplicating
+    // the entry point.
+    // "gcc" can suppress code duplication with suitable function
+    // attributes, but "clang" doesn't have this ability.
+    // The "clang" developer mailing list suggested that the correct
+    // and portable solution is a file-scope assembly block.
+    // N.B. We do mark our code as a proper function so that backtraces
+    // work correctly. But we make absolutely no attempt to use the
+    // ABI's calling conventions for passing arguments. We will only
+    // ever be called from assembly code and thus can pick more
+    // suitable calling conventions.
+#if defined(__i386__)
+    ".text\n"
+    ".align 16, 0x90\n"
+    ".type SyscallAsm, @function\n"
+    "SyscallAsm:.cfi_startproc\n"
+    // Check if "%eax" is negative. If so, do not attempt to make a
+    // system call. Instead, compute the return address that is visible
+    // to the kernel after we execute "int $0x80". This address can be
+    // used as a marker that BPF code inspects.
+    "test %eax, %eax\n"
+    "jge  1f\n"
+    // Always, make sure that our code is position-independent, or
+    // address space randomization might not work on i386. This means,
+    // we can't use "lea", but instead have to rely on "call/pop".
+    "call 0f;   .cfi_adjust_cfa_offset  4\n"
+    "0:pop  %eax; .cfi_adjust_cfa_offset -4\n"
+    "addl $2f-0b, %eax\n"
+    "ret\n"
+    // Save register that we don't want to clobber. On i386, we need to
+    // save relatively aggressively, as there are a couple or registers
+    // that are used internally (e.g. %ebx for position-independent
+    // code, and %ebp for the frame pointer), and as we need to keep at
+    // least a few registers available for the register allocator.
+    "1:push %esi; .cfi_adjust_cfa_offset 4\n"
+    "push %edi; .cfi_adjust_cfa_offset 4\n"
+    "push %ebx; .cfi_adjust_cfa_offset 4\n"
+    "push %ebp; .cfi_adjust_cfa_offset 4\n"
+    // Copy entries from the array holding the arguments into the
+    // correct CPU registers.
+    "movl  0(%edi), %ebx\n"
+    "movl  4(%edi), %ecx\n"
+    "movl  8(%edi), %edx\n"
+    "movl 12(%edi), %esi\n"
+    "movl 20(%edi), %ebp\n"
+    "movl 16(%edi), %edi\n"
+    // Enter the kernel.
+    "int  $0x80\n"
+    // This is our "magic" return address that the BPF filter sees.
+    "2:"
+    // Restore any clobbered registers that we didn't declare to the
+    // compiler.
+    "pop  %ebp; .cfi_adjust_cfa_offset -4\n"
+    "pop  %ebx; .cfi_adjust_cfa_offset -4\n"
+    "pop  %edi; .cfi_adjust_cfa_offset -4\n"
+    "pop  %esi; .cfi_adjust_cfa_offset -4\n"
+    "ret\n"
+    ".cfi_endproc\n"
+    "9:.size SyscallAsm, 9b-SyscallAsm\n"
+#elif defined(__x86_64__)
+    ".text\n"
+    ".align 16, 0x90\n"
+    ".type SyscallAsm, @function\n"
+    "SyscallAsm:.cfi_startproc\n"
+    // Check if "%rax" is negative. If so, do not attempt to make a
+    // system call. Instead, compute the return address that is visible
+    // to the kernel after we execute "syscall". This address can be
+    // used as a marker that BPF code inspects.
+    "test %rax, %rax\n"
+    "jge  1f\n"
+    // Always make sure that our code is position-independent, or the
+    // linker will throw a hissy fit on x86-64.
+    "call 0f;   .cfi_adjust_cfa_offset  8\n"
+    "0:pop  %rax; .cfi_adjust_cfa_offset -8\n"
+    "addq $2f-0b, %rax\n"
+    "ret\n"
+    // We declared all clobbered registers to the compiler. On x86-64,
+    // there really isn't much of a problem with register pressure. So,
+    // we can go ahead and directly copy the entries from the arguments
+    // array into the appropriate CPU registers.
+    "1:movq  0(%r12), %rdi\n"
+    "movq  8(%r12), %rsi\n"
+    "movq 16(%r12), %rdx\n"
+    "movq 24(%r12), %r10\n"
+    "movq 32(%r12), %r8\n"
+    "movq 40(%r12), %r9\n"
+    // Enter the kernel.
+    "syscall\n"
+    // This is our "magic" return address that the BPF filter sees.
+    "2:ret\n"
+    ".cfi_endproc\n"
+    "9:.size SyscallAsm, 9b-SyscallAsm\n"
+#elif defined(__arm__)
+    // Throughout this file, we use the same mode (ARM vs. thumb)
+    // that the C++ compiler uses. This means, when transfering control
+    // from C++ to assembly code, we do not need to switch modes (e.g.
+    // by using the "bx" instruction). It also means that our assembly
+    // code should not be invoked directly from code that lives in
+    // other compilation units, as we don't bother implementing thumb
+    // interworking. That's OK, as we don't make any of the assembly
+    // symbols public. They are all local to this file.
+    ".text\n"
+    ".align 2\n"
+    ".type SyscallAsm, %function\n"
+#if defined(__thumb__)
+    ".thumb_func\n"
+#else
+    ".arm\n"
+#endif
+    "SyscallAsm:.fnstart\n"
+    "@ args = 0, pretend = 0, frame = 8\n"
+    "@ frame_needed = 1, uses_anonymous_args = 0\n"
+#if defined(__thumb__)
+    ".cfi_startproc\n"
+    "push {r7, lr}\n"
+    ".cfi_offset 14, -4\n"
+    ".cfi_offset  7, -8\n"
+    "mov r7, sp\n"
+    ".cfi_def_cfa_register 7\n"
+    ".cfi_def_cfa_offset 8\n"
+#else
+    "stmfd sp!, {fp, lr}\n"
+    "add fp, sp, #4\n"
+#endif
+    // Check if "r0" is negative. If so, do not attempt to make a
+    // system call. Instead, compute the return address that is visible
+    // to the kernel after we execute "swi 0". This address can be
+    // used as a marker that BPF code inspects.
+    "cmp r0, #0\n"
+    "bge 1f\n"
+    "adr r0, 2f\n"
+    "b   2f\n"
+    // We declared (almost) all clobbered registers to the compiler. On
+    // ARM there is no particular register pressure. So, we can go
+    // ahead and directly copy the entries from the arguments array
+    // into the appropriate CPU registers.
+    "1:ldr r5, [r6, #20]\n"
+    "ldr r4, [r6, #16]\n"
+    "ldr r3, [r6, #12]\n"
+    "ldr r2, [r6, #8]\n"
+    "ldr r1, [r6, #4]\n"
+    "mov r7, r0\n"
+    "ldr r0, [r6, #0]\n"
+    // Enter the kernel
+    "swi 0\n"
+// Restore the frame pointer. Also restore the program counter from
+// the link register; this makes us return to the caller.
+#if defined(__thumb__)
+    "2:pop {r7, pc}\n"
+    ".cfi_endproc\n"
+#else
+    "2:ldmfd sp!, {fp, pc}\n"
+#endif
+    ".fnend\n"
+    "9:.size SyscallAsm, 9b-SyscallAsm\n"
+#endif
+    );  // asm
+
+}  // namespace
+
+intptr_t Syscall::Call(int nr,
+                       intptr_t p0,
+                       intptr_t p1,
+                       intptr_t p2,
+                       intptr_t p3,
+                       intptr_t p4,
+                       intptr_t p5) {
   // We rely on "intptr_t" to be the exact size as a "void *". This is
   // typically true, but just in case, we add a check. The language
   // specification allows platforms some leeway in cases, where
@@ -181,61 +189,78 @@
   // that this would only be an issue for IA64, which we are currently not
   // planning on supporting. And it is even possible that this would work
   // on IA64, but for lack of actual hardware, I cannot test.
-  COMPILE_ASSERT(sizeof(void *) == sizeof(intptr_t),
+  COMPILE_ASSERT(sizeof(void*) == sizeof(intptr_t),
                  pointer_types_and_intptr_must_be_exactly_the_same_size);
 
-  const intptr_t args[6] = { p0, p1, p2, p3, p4, p5 };
+  const intptr_t args[6] = {p0, p1, p2, p3, p4, p5};
 
-  // Invoke our file-scope assembly code. The constraints have been picked
-  // carefully to match what the rest of the assembly code expects in input,
-  // output, and clobbered registers.
+// Invoke our file-scope assembly code. The constraints have been picked
+// carefully to match what the rest of the assembly code expects in input,
+// output, and clobbered registers.
 #if defined(__i386__)
   intptr_t ret = nr;
   asm volatile(
-    "call SyscallAsm\n"
-    // N.B. These are not the calling conventions normally used by the ABI.
-    : "=a"(ret)
-    : "0"(ret), "D"(args)
-    : "cc", "esp", "memory", "ecx", "edx");
+      "call SyscallAsm\n"
+      // N.B. These are not the calling conventions normally used by the ABI.
+      : "=a"(ret)
+      : "0"(ret), "D"(args)
+      : "cc", "esp", "memory", "ecx", "edx");
 #elif defined(__x86_64__)
   intptr_t ret = nr;
   {
-    register const intptr_t *data __asm__("r12") = args;
+    register const intptr_t* data __asm__("r12") = args;
     asm volatile(
-      "lea  -128(%%rsp), %%rsp\n"  // Avoid red zone.
-      "call SyscallAsm\n"
-      "lea  128(%%rsp), %%rsp\n"
-      // N.B. These are not the calling conventions normally used by the ABI.
-      : "=a"(ret)
-      : "0"(ret), "r"(data)
-      : "cc", "rsp", "memory",
-        "rcx", "rdi", "rsi", "rdx", "r8", "r9", "r10", "r11");
+        "lea  -128(%%rsp), %%rsp\n"  // Avoid red zone.
+        "call SyscallAsm\n"
+        "lea  128(%%rsp), %%rsp\n"
+        // N.B. These are not the calling conventions normally used by the ABI.
+        : "=a"(ret)
+        : "0"(ret), "r"(data)
+        : "cc",
+          "rsp",
+          "memory",
+          "rcx",
+          "rdi",
+          "rsi",
+          "rdx",
+          "r8",
+          "r9",
+          "r10",
+          "r11");
   }
 #elif defined(__arm__)
   intptr_t ret;
   {
     register intptr_t inout __asm__("r0") = nr;
-    register const intptr_t *data __asm__("r6") = args;
+    register const intptr_t* data __asm__("r6") = args;
     asm volatile(
-      "bl SyscallAsm\n"
-      // N.B. These are not the calling conventions normally used by the ABI.
-      : "=r"(inout)
-      : "0"(inout), "r"(data)
-      : "cc", "lr", "memory", "r1", "r2", "r3", "r4", "r5"
+        "bl SyscallAsm\n"
+        // N.B. These are not the calling conventions normally used by the ABI.
+        : "=r"(inout)
+        : "0"(inout), "r"(data)
+        : "cc",
+          "lr",
+          "memory",
+          "r1",
+          "r2",
+          "r3",
+          "r4",
+          "r5"
 #if !defined(__thumb__)
-      // In thumb mode, we cannot use "r7" as a general purpose register, as
-      // it is our frame pointer. We have to manually manage and preserve it.
-      // In ARM mode, we have a dedicated frame pointer register and "r7" is
-      // thus available as a general purpose register. We don't preserve it,
-      // but instead mark it as clobbered.
-        , "r7"
+          // In thumb mode, we cannot use "r7" as a general purpose register, as
+          // it is our frame pointer. We have to manually manage and preserve
+          // it.
+          // In ARM mode, we have a dedicated frame pointer register and "r7" is
+          // thus available as a general purpose register. We don't preserve it,
+          // but instead mark it as clobbered.
+          ,
+          "r7"
 #endif  // !defined(__thumb__)
-      );
+        );
     ret = inout;
   }
 #else
-  errno = ENOSYS;
-  intptr_t ret = -1;
+#error "Unimplemented architecture"
 #endif
   return ret;
 }
diff --git a/sandbox/linux/seccomp-bpf/syscall.h b/sandbox/linux/seccomp-bpf/syscall.h
index f444d3a..57970a3 100644
--- a/sandbox/linux/seccomp-bpf/syscall.h
+++ b/sandbox/linux/seccomp-bpf/syscall.h
@@ -7,141 +7,82 @@
 
 #include <stdint.h>
 
+#include "base/macros.h"
 #include "sandbox/sandbox_export.h"
 
 namespace sandbox {
 
-// We have to make sure that we have a single "magic" return address for
-// our system calls, which we can check from within a BPF filter. This
-// works by writing a little bit of asm() code that a) enters the kernel, and
-// that also b) can be invoked in a way that computes this return address.
-// Passing "nr" as "-1" computes the "magic" return address. Passing any
-// other value invokes the appropriate system call.
-SANDBOX_EXPORT intptr_t SandboxSyscall(int nr,
-                                       intptr_t p0,
-                                       intptr_t p1,
-                                       intptr_t p2,
-                                       intptr_t p3,
-                                       intptr_t p4,
-                                       intptr_t p5);
+// This purely static class can be used to perform system calls with some
+// low-level control.
+class SANDBOX_EXPORT Syscall {
+ public:
+  // This performs system call |nr| with the arguments p0 to p5 from a constant
+  // userland address, which is for instance observable by seccomp-bpf filters.
+  // The constant userland address from which these system calls are made will
+  // be returned if |nr| is passed as -1.
+  // On error, this function will return a value between -1 and -4095 which
+  // should be interpreted as -errno.
+  static intptr_t Call(int nr,
+                       intptr_t p0,
+                       intptr_t p1,
+                       intptr_t p2,
+                       intptr_t p3,
+                       intptr_t p4,
+                       intptr_t p5);
 
-// System calls can take up to six parameters. Traditionally, glibc
-// implements this property by using variadic argument lists. This works, but
-// confuses modern tools such as valgrind, because we are nominally passing
-// uninitialized data whenever we call through this function and pass less
-// than the full six arguments.
-// So, instead, we use C++'s template system to achieve a very similar
-// effect. C++ automatically sets the unused parameters to zero for us, and
-// it also does the correct type expansion (e.g. from 32bit to 64bit) where
-// necessary.
-// We have to use C-style cast operators as we want to be able to accept both
-// integer and pointer types.
-// We explicitly mark all functions as inline. This is not necessary in
-// optimized builds, where the compiler automatically figures out that it
-// can inline everything. But it makes stack traces of unoptimized builds
-// easier to read as it hides implementation details.
-#if __cplusplus >= 201103  // C++11
+  // System calls can take up to six parameters. Traditionally, glibc
+  // implements this property by using variadic argument lists. This works, but
+  // confuses modern tools such as valgrind, because we are nominally passing
+  // uninitialized data whenever we call through this function and pass less
+  // than the full six arguments.
+  // So, instead, we use C++'s template system to achieve a very similar
+  // effect. C++ automatically sets the unused parameters to zero for us, and
+  // it also does the correct type expansion (e.g. from 32bit to 64bit) where
+  // necessary.
+  // We have to use C-style cast operators as we want to be able to accept both
+  // integer and pointer types.
+  template <class T0, class T1, class T2, class T3, class T4, class T5>
+  static inline intptr_t
+  Call(int nr, T0 p0, T1 p1, T2 p2, T3 p3, T4 p4, T5 p5) {
+    return Call(nr,
+                (intptr_t)p0,
+                (intptr_t)p1,
+                (intptr_t)p2,
+                (intptr_t)p3,
+                (intptr_t)p4,
+                (intptr_t)p5);
+  }
 
-template <class T0 = intptr_t,
-          class T1 = intptr_t,
-          class T2 = intptr_t,
-          class T3 = intptr_t,
-          class T4 = intptr_t,
-          class T5 = intptr_t>
-SANDBOX_EXPORT inline intptr_t SandboxSyscall(int nr,
-                                              T0 p0 = 0,
-                                              T1 p1 = 0,
-                                              T2 p2 = 0,
-                                              T3 p3 = 0,
-                                              T4 p4 = 0,
-                                              T5 p5 = 0)
-    __attribute__((always_inline));
+  template <class T0, class T1, class T2, class T3, class T4>
+  static inline intptr_t Call(int nr, T0 p0, T1 p1, T2 p2, T3 p3, T4 p4) {
+    return Call(nr, p0, p1, p2, p3, p4, 0);
+  }
 
-template <class T0, class T1, class T2, class T3, class T4, class T5>
-SANDBOX_EXPORT inline intptr_t
-SandboxSyscall(int nr, T0 p0, T1 p1, T2 p2, T3 p3, T4 p4, T5 p5) {
-  return SandboxSyscall(nr,
-                        (intptr_t)p0,
-                        (intptr_t)p1,
-                        (intptr_t)p2,
-                        (intptr_t)p3,
-                        (intptr_t)p4,
-                        (intptr_t)p5);
-}
+  template <class T0, class T1, class T2, class T3>
+  static inline intptr_t Call(int nr, T0 p0, T1 p1, T2 p2, T3 p3) {
+    return Call(nr, p0, p1, p2, p3, 0, 0);
+  }
 
-#else  // Pre-C++11
+  template <class T0, class T1, class T2>
+  static inline intptr_t Call(int nr, T0 p0, T1 p1, T2 p2) {
+    return Call(nr, p0, p1, p2, 0, 0, 0);
+  }
 
-// TODO(markus): C++11 has a much more concise and readable solution for
-//   expressing what we are doing here. Delete the fall-back code for older
-//   compilers as soon as we have fully switched to C++11
+  template <class T0, class T1>
+  static inline intptr_t Call(int nr, T0 p0, T1 p1) {
+    return Call(nr, p0, p1, 0, 0, 0, 0);
+  }
 
-template <class T0, class T1, class T2, class T3, class T4, class T5>
-SANDBOX_EXPORT inline intptr_t
-    SandboxSyscall(int nr, T0 p0, T1 p1, T2 p2, T3 p3, T4 p4, T5 p5)
-    __attribute__((always_inline));
-template <class T0, class T1, class T2, class T3, class T4, class T5>
-SANDBOX_EXPORT inline intptr_t
-SandboxSyscall(int nr, T0 p0, T1 p1, T2 p2, T3 p3, T4 p4, T5 p5) {
-  return SandboxSyscall(nr,
-                        (intptr_t)p0,
-                        (intptr_t)p1,
-                        (intptr_t)p2,
-                        (intptr_t)p3,
-                        (intptr_t)p4,
-                        (intptr_t)p5);
-}
+  template <class T0>
+  static inline intptr_t Call(int nr, T0 p0) {
+    return Call(nr, p0, 0, 0, 0, 0, 0);
+  }
 
-template <class T0, class T1, class T2, class T3, class T4>
-SANDBOX_EXPORT inline intptr_t
-    SandboxSyscall(int nr, T0 p0, T1 p1, T2 p2, T3 p3, T4 p4)
-    __attribute__((always_inline));
-template <class T0, class T1, class T2, class T3, class T4>
-SANDBOX_EXPORT inline intptr_t
-SandboxSyscall(int nr, T0 p0, T1 p1, T2 p2, T3 p3, T4 p4) {
-  return SandboxSyscall(nr, p0, p1, p2, p3, p4, 0);
-}
+  static inline intptr_t Call(int nr) { return Call(nr, 0, 0, 0, 0, 0, 0); }
 
-template <class T0, class T1, class T2, class T3>
-SANDBOX_EXPORT inline intptr_t
-    SandboxSyscall(int nr, T0 p0, T1 p1, T2 p2, T3 p3)
-    __attribute__((always_inline));
-template <class T0, class T1, class T2, class T3>
-SANDBOX_EXPORT inline intptr_t
-SandboxSyscall(int nr, T0 p0, T1 p1, T2 p2, T3 p3) {
-  return SandboxSyscall(nr, p0, p1, p2, p3, 0, 0);
-}
-
-template <class T0, class T1, class T2>
-SANDBOX_EXPORT inline intptr_t SandboxSyscall(int nr, T0 p0, T1 p1, T2 p2)
-    __attribute__((always_inline));
-template <class T0, class T1, class T2>
-SANDBOX_EXPORT inline intptr_t SandboxSyscall(int nr, T0 p0, T1 p1, T2 p2) {
-  return SandboxSyscall(nr, p0, p1, p2, 0, 0, 0);
-}
-
-template <class T0, class T1>
-SANDBOX_EXPORT inline intptr_t SandboxSyscall(int nr, T0 p0, T1 p1)
-    __attribute__((always_inline));
-template <class T0, class T1>
-SANDBOX_EXPORT inline intptr_t SandboxSyscall(int nr, T0 p0, T1 p1) {
-  return SandboxSyscall(nr, p0, p1, 0, 0, 0, 0);
-}
-
-template <class T0>
-SANDBOX_EXPORT inline intptr_t SandboxSyscall(int nr, T0 p0)
-    __attribute__((always_inline));
-template <class T0>
-SANDBOX_EXPORT inline intptr_t SandboxSyscall(int nr, T0 p0) {
-  return SandboxSyscall(nr, p0, 0, 0, 0, 0, 0);
-}
-
-SANDBOX_EXPORT inline intptr_t SandboxSyscall(int nr)
-    __attribute__((always_inline));
-SANDBOX_EXPORT inline intptr_t SandboxSyscall(int nr) {
-  return SandboxSyscall(nr, 0, 0, 0, 0, 0, 0);
-}
-
-#endif  // Pre-C++11
+ private:
+  DISALLOW_IMPLICIT_CONSTRUCTORS(Syscall);
+};
 
 }  // namespace sandbox
 
diff --git a/sandbox/linux/seccomp-bpf/syscall_unittest.cc b/sandbox/linux/seccomp-bpf/syscall_unittest.cc
index bdeee4f..80b5079 100644
--- a/sandbox/linux/seccomp-bpf/syscall_unittest.cc
+++ b/sandbox/linux/seccomp-bpf/syscall_unittest.cc
@@ -12,6 +12,7 @@
 
 #include "base/basictypes.h"
 #include "base/posix/eintr_wrapper.h"
+#include "build/build_config.h"
 #include "sandbox/linux/seccomp-bpf/bpf_tests.h"
 #include "sandbox/linux/seccomp-bpf/sandbox_bpf.h"
 #include "sandbox/linux/seccomp-bpf/syscall.h"
@@ -31,24 +32,25 @@
 #endif
 
 TEST(Syscall, WellKnownEntryPoint) {
-// Test that SandboxSyscall(-1) is handled specially. Don't do this on ARM,
+// Test that Syscall::Call(-1) is handled specially. Don't do this on ARM,
 // where syscall(-1) crashes with SIGILL. Not running the test is fine, as we
 // are still testing ARM code in the next set of tests.
 #if !defined(__arm__)
-  EXPECT_NE(SandboxSyscall(-1), syscall(-1));
+  EXPECT_NE(Syscall::Call(-1), syscall(-1));
 #endif
 
-// If possible, test that SandboxSyscall(-1) returns the address right after
+// If possible, test that Syscall::Call(-1) returns the address right
+// after
 // a kernel entry point.
 #if defined(__i386__)
-  EXPECT_EQ(0x80CDu, ((uint16_t*)SandboxSyscall(-1))[-1]);  // INT 0x80
+  EXPECT_EQ(0x80CDu, ((uint16_t*)Syscall::Call(-1))[-1]);  // INT 0x80
 #elif defined(__x86_64__)
-  EXPECT_EQ(0x050Fu, ((uint16_t*)SandboxSyscall(-1))[-1]);  // SYSCALL
+  EXPECT_EQ(0x050Fu, ((uint16_t*)Syscall::Call(-1))[-1]);  // SYSCALL
 #elif defined(__arm__)
 #if defined(__thumb__)
-  EXPECT_EQ(0xDF00u, ((uint16_t*)SandboxSyscall(-1))[-1]);  // SWI 0
+  EXPECT_EQ(0xDF00u, ((uint16_t*)Syscall::Call(-1))[-1]);  // SWI 0
 #else
-  EXPECT_EQ(0xEF000000u, ((uint32_t*)SandboxSyscall(-1))[-1]);  // SVC 0
+  EXPECT_EQ(0xEF000000u, ((uint32_t*)Syscall::Call(-1))[-1]);  // SVC 0
 #endif
 #else
 #warning Incomplete test case; need port for target platform
@@ -57,17 +59,25 @@
 
 TEST(Syscall, TrivialSyscallNoArgs) {
   // Test that we can do basic system calls
-  EXPECT_EQ(SandboxSyscall(__NR_getpid), syscall(__NR_getpid));
+  EXPECT_EQ(Syscall::Call(__NR_getpid), syscall(__NR_getpid));
 }
 
 TEST(Syscall, TrivialSyscallOneArg) {
   int new_fd;
   // Duplicate standard error and close it.
-  ASSERT_GE(new_fd = SandboxSyscall(__NR_dup, 2), 0);
-  int close_return_value = IGNORE_EINTR(SandboxSyscall(__NR_close, new_fd));
+  ASSERT_GE(new_fd = Syscall::Call(__NR_dup, 2), 0);
+  int close_return_value = IGNORE_EINTR(Syscall::Call(__NR_close, new_fd));
   ASSERT_EQ(close_return_value, 0);
 }
 
+TEST(Syscall, TrivialFailingSyscall) {
+  errno = -42;
+  int ret = Syscall::Call(__NR_dup, -1);
+  ASSERT_EQ(-EBADF, ret);
+  // Verify that Syscall::Call does not touch errno.
+  ASSERT_EQ(-42, errno);
+}
+
 // SIGSYS trap handler that will be called on __NR_uname.
 intptr_t CopySyscallArgsToAux(const struct arch_seccomp_data& args, void* aux) {
   // |aux| is our BPF_AUX pointer.
@@ -91,7 +101,8 @@
   }
 }
 
-// We are testing SandboxSyscall() by making use of a BPF filter that allows us
+// We are testing Syscall::Call() by making use of a BPF filter that
+// allows us
 // to inspect the system call arguments that the kernel saw.
 BPF_TEST(Syscall,
          SyntheticSixArgs,
@@ -109,13 +120,13 @@
 
   // We could use pretty much any system call we don't need here. uname() is
   // nice because it doesn't have any dangerous side effects.
-  BPF_ASSERT(SandboxSyscall(__NR_uname,
-                            syscall_args[0],
-                            syscall_args[1],
-                            syscall_args[2],
-                            syscall_args[3],
-                            syscall_args[4],
-                            syscall_args[5]) == -ENOMEM);
+  BPF_ASSERT(Syscall::Call(__NR_uname,
+                           syscall_args[0],
+                           syscall_args[1],
+                           syscall_args[2],
+                           syscall_args[3],
+                           syscall_args[4],
+                           syscall_args[5]) == -ENOMEM);
 
   // We expect the trap handler to have copied the 6 arguments.
   BPF_ASSERT(BPF_AUX->size() == 6);
@@ -133,69 +144,69 @@
 
 TEST(Syscall, ComplexSyscallSixArgs) {
   int fd;
-  ASSERT_LE(0, fd = SandboxSyscall(__NR_open, "/dev/null", O_RDWR, 0L));
+  ASSERT_LE(0, fd = Syscall::Call(__NR_open, "/dev/null", O_RDWR, 0L));
 
   // Use mmap() to allocate some read-only memory
   char* addr0;
-  ASSERT_NE((char*)NULL,
-            addr0 = reinterpret_cast<char*>(
-                SandboxSyscall(kMMapNr,
-                               (void*)NULL,
-                               4096,
-                               PROT_READ,
-                               MAP_PRIVATE | MAP_ANONYMOUS,
-                               fd,
-                               0L)));
+  ASSERT_NE(
+      (char*)NULL,
+      addr0 = reinterpret_cast<char*>(Syscall::Call(kMMapNr,
+                                                    (void*)NULL,
+                                                    4096,
+                                                    PROT_READ,
+                                                    MAP_PRIVATE | MAP_ANONYMOUS,
+                                                    fd,
+                                                    0L)));
 
   // Try to replace the existing mapping with a read-write mapping
   char* addr1;
   ASSERT_EQ(addr0,
             addr1 = reinterpret_cast<char*>(
-                SandboxSyscall(kMMapNr,
-                               addr0,
-                               4096L,
-                               PROT_READ | PROT_WRITE,
-                               MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED,
-                               fd,
-                               0L)));
+                Syscall::Call(kMMapNr,
+                              addr0,
+                              4096L,
+                              PROT_READ | PROT_WRITE,
+                              MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED,
+                              fd,
+                              0L)));
   ++*addr1;  // This should not seg fault
 
   // Clean up
-  EXPECT_EQ(0, SandboxSyscall(__NR_munmap, addr1, 4096L));
-  EXPECT_EQ(0, IGNORE_EINTR(SandboxSyscall(__NR_close, fd)));
+  EXPECT_EQ(0, Syscall::Call(__NR_munmap, addr1, 4096L));
+  EXPECT_EQ(0, IGNORE_EINTR(Syscall::Call(__NR_close, fd)));
 
   // Check that the offset argument (i.e. the sixth argument) is processed
   // correctly.
-  ASSERT_GE(fd = SandboxSyscall(__NR_open, "/proc/self/exe", O_RDONLY, 0L), 0);
+  ASSERT_GE(fd = Syscall::Call(__NR_open, "/proc/self/exe", O_RDONLY, 0L), 0);
   char* addr2, *addr3;
   ASSERT_NE((char*)NULL,
-            addr2 = reinterpret_cast<char*>(SandboxSyscall(
+            addr2 = reinterpret_cast<char*>(Syscall::Call(
                 kMMapNr, (void*)NULL, 8192L, PROT_READ, MAP_PRIVATE, fd, 0L)));
   ASSERT_NE((char*)NULL,
-            addr3 = reinterpret_cast<char*>(SandboxSyscall(kMMapNr,
-                                                           (void*)NULL,
-                                                           4096L,
-                                                           PROT_READ,
-                                                           MAP_PRIVATE,
-                                                           fd,
+            addr3 = reinterpret_cast<char*>(Syscall::Call(kMMapNr,
+                                                          (void*)NULL,
+                                                          4096L,
+                                                          PROT_READ,
+                                                          MAP_PRIVATE,
+                                                          fd,
 #if defined(__NR_mmap2)
-                                                           1L
+                                                          1L
 #else
-                                                           4096L
+                                                          4096L
 #endif
-                                                           )));
+                                                          )));
   EXPECT_EQ(0, memcmp(addr2 + 4096, addr3, 4096));
 
   // Just to be absolutely on the safe side, also verify that the file
   // contents matches what we are getting from a read() operation.
   char buf[8192];
-  EXPECT_EQ(8192, SandboxSyscall(__NR_read, fd, buf, 8192L));
+  EXPECT_EQ(8192, Syscall::Call(__NR_read, fd, buf, 8192L));
   EXPECT_EQ(0, memcmp(addr2, buf, 8192));
 
   // Clean up
-  EXPECT_EQ(0, SandboxSyscall(__NR_munmap, addr2, 8192L));
-  EXPECT_EQ(0, SandboxSyscall(__NR_munmap, addr3, 4096L));
-  EXPECT_EQ(0, IGNORE_EINTR(SandboxSyscall(__NR_close, fd)));
+  EXPECT_EQ(0, Syscall::Call(__NR_munmap, addr2, 8192L));
+  EXPECT_EQ(0, Syscall::Call(__NR_munmap, addr3, 4096L));
+  EXPECT_EQ(0, IGNORE_EINTR(Syscall::Call(__NR_close, fd)));
 }
 
 }  // namespace
diff --git a/sandbox/linux/seccomp-bpf/trap.cc b/sandbox/linux/seccomp-bpf/trap.cc
index f8b64c9..4c42111 100644
--- a/sandbox/linux/seccomp-bpf/trap.cc
+++ b/sandbox/linux/seccomp-bpf/trap.cc
@@ -168,13 +168,13 @@
     if (sigsys.nr == __NR_clone) {
       RAW_SANDBOX_DIE("Cannot call clone() from an UnsafeTrap() handler.");
     }
-    rc = SandboxSyscall(sigsys.nr,
-                        SECCOMP_PARM1(ctx),
-                        SECCOMP_PARM2(ctx),
-                        SECCOMP_PARM3(ctx),
-                        SECCOMP_PARM4(ctx),
-                        SECCOMP_PARM5(ctx),
-                        SECCOMP_PARM6(ctx));
+    rc = Syscall::Call(sigsys.nr,
+                       SECCOMP_PARM1(ctx),
+                       SECCOMP_PARM2(ctx),
+                       SECCOMP_PARM3(ctx),
+                       SECCOMP_PARM4(ctx),
+                       SECCOMP_PARM5(ctx),
+                       SECCOMP_PARM6(ctx));
   } else {
     const ErrorCode& err = trap_array_[info->si_errno - 1];
     if (!err.safe_) {
@@ -227,7 +227,7 @@
     // we never return an ErrorCode that is marked as "unsafe". This also
     // means, the BPF compiler will never emit code that allow unsafe system
     // calls to by-pass the filter (because they use the magic return address
-    // from SandboxSyscall(-1)).
+    // from Syscall::Call(-1)).
 
     // This SANDBOX_DIE() can optionally be removed. It won't break security,
     // but it might make error messages from the BPF compiler a little harder
diff --git a/sandbox/linux/seccomp-bpf/verifier.cc b/sandbox/linux/seccomp-bpf/verifier.cc
index 07b13d6..0863556 100644
--- a/sandbox/linux/seccomp-bpf/verifier.cc
+++ b/sandbox/linux/seccomp-bpf/verifier.cc
@@ -423,10 +423,10 @@
         switch (r & SECCOMP_RET_ACTION) {
           case SECCOMP_RET_TRAP:
           case SECCOMP_RET_ERRNO:
+          case SECCOMP_RET_TRACE:
           case SECCOMP_RET_ALLOW:
             break;
           case SECCOMP_RET_KILL:     // We don't ever generate this
-          case SECCOMP_RET_TRACE:    // We don't ever generate this
           case SECCOMP_RET_INVALID:  // Should never show up in BPF program
           default:
             *err = "Unexpected return code found in BPF program";
diff --git a/sandbox/linux/tests/main.cc b/sandbox/linux/tests/main.cc
index 9ee384d..81a0b32 100644
--- a/sandbox/linux/tests/main.cc
+++ b/sandbox/linux/tests/main.cc
@@ -23,11 +23,21 @@
 }  // namespace
 }  // namespace sandbox
 
+#if defined(OS_ANDROID)
+void UnitTestAssertHandler(const std::string& str) {
+  _exit(1);
+}
+#endif
+
 int main(int argc, char* argv[]) {
 #if defined(OS_ANDROID)
   // The use of Callbacks requires an AtExitManager.
   base::AtExitManager exit_manager;
   testing::InitGoogleTest(&argc, argv);
+  // Death tests rely on LOG(FATAL) triggering an exit (the default behavior is
+  // SIGABRT).  The normal test launcher does this at initialization, but since
+  // we still do not use this on Android, we must install the handler ourselves.
+  logging::SetLogAssertHandler(UnitTestAssertHandler);
 #endif
   // Always go through re-execution for death tests.
   // This makes gtest only marginally slower for us and has the
diff --git a/sandbox/mac/BUILD.gn b/sandbox/mac/BUILD.gn
new file mode 100644
index 0000000..e615197
--- /dev/null
+++ b/sandbox/mac/BUILD.gn
@@ -0,0 +1,72 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+component("sandbox") {
+  sources = [
+    "bootstrap_sandbox.cc",
+    "bootstrap_sandbox.h",
+    "launchd_interception_server.cc",
+    "launchd_interception_server.h",
+    "mach_message_server.cc",
+    "mach_message_server.h",
+    "os_compatibility.cc",
+    "os_compatibility.h",
+    "policy.cc",
+    "policy.h",
+    "xpc.h",
+  ]
+
+  defines = [ "SANDBOX_IMPLEMENTATION" ]
+  libs = [ "bsm" ]
+
+  deps = [
+    "//base",
+    ":generate_stubs",
+  ]
+}
+
+generate_stubs_script = "//tools/generate_stubs/generate_stubs.py"
+generate_stubs_header = "xpc_stubs_header.fragment"
+generate_stubs_sig_public = "xpc_stubs.sig"
+generate_stubs_sig_private = "xpc_private_stubs.sig"
+generate_stubs_project = "sandbox/mac"
+generate_stubs_output_stem = "xpc_stubs"
+
+action("generate_stubs") {
+  script = generate_stubs_script
+  sources = [ generate_stubs_sig_public, generate_stubs_sig_private ]
+  source_prereqs = [ generate_stubs_header ]
+  outputs = [
+    "$target_gen_dir/$generate_stubs_output_stem.cc",
+    "$target_gen_dir/$generate_stubs_output_stem.h",
+  ]
+  args = [
+    "-i", rebase_path(target_gen_dir, root_build_dir),
+    "-o", rebase_path(target_gen_dir, root_build_dir),
+    "-t", "posix_stubs",
+    "-e", rebase_path(generate_stubs_header, root_build_dir),
+    "-s", generate_stubs_output_stem,
+    "-p", generate_stubs_project,
+  ]
+  args += rebase_path(sources, root_build_dir)
+}
+
+test("sandbox_mac_unittests") {
+  sources = [
+    "bootstrap_sandbox_unittest.mm",
+    "policy_unittest.cc",
+  ]
+
+  libs = [
+    "CoreFoundation.framework",
+    "Foundation.framework",
+  ]
+
+  deps = [
+    ":sandbox",
+    "//base",
+    "//base/test:run_all_unittests",
+    "//testing/gtest",
+  ]
+}
diff --git a/sandbox/mac/bootstrap_sandbox.cc b/sandbox/mac/bootstrap_sandbox.cc
index b90d8d1..6407c68 100644
--- a/sandbox/mac/bootstrap_sandbox.cc
+++ b/sandbox/mac/bootstrap_sandbox.cc
@@ -60,7 +60,7 @@
     int sandbox_policy_id,
     const BootstrapSandboxPolicy& policy) {
   CHECK(IsPolicyValid(policy));
-  CHECK_GT(sandbox_policy_id, 0);
+  CHECK_GT(sandbox_policy_id, kNotAPolicy);
   base::AutoLock lock(lock_);
   DCHECK(policies_.find(sandbox_policy_id) == policies_.end());
   policies_.insert(std::make_pair(sandbox_policy_id, policy));
@@ -102,8 +102,8 @@
 void BootstrapSandbox::ChildDied(base::ProcessHandle handle) {
   base::AutoLock lock(lock_);
   const auto& it = sandboxed_processes_.find(handle);
-  CHECK(it != sandboxed_processes_.end());
-  sandboxed_processes_.erase(it);
+  if (it != sandboxed_processes_.end())
+    sandboxed_processes_.erase(it);
 }
 
 const BootstrapSandboxPolicy* BootstrapSandbox::PolicyForProcess(
diff --git a/sandbox/mac/launchd_interception_server.cc b/sandbox/mac/launchd_interception_server.cc
index 57264aa..70fd33e 100644
--- a/sandbox/mac/launchd_interception_server.cc
+++ b/sandbox/mac/launchd_interception_server.cc
@@ -4,7 +4,6 @@
 
 #include "sandbox/mac/launchd_interception_server.h"
 
-#include <bsm/libbsm.h>
 #include <servers/bootstrap.h>
 
 #include "base/logging.h"
@@ -16,60 +15,24 @@
 // The buffer size for all launchd messages. This comes from
 // sizeof(union __RequestUnion__vproc_mig_job_subsystem) in launchd, and it
 // is larger than the __ReplyUnion.
-const mach_msg_size_t kBufferSize = mach_vm_round_page(2096 +
-    sizeof(mach_msg_audit_trailer_t));
+const mach_msg_size_t kBufferSize = 2096;
 
 LaunchdInterceptionServer::LaunchdInterceptionServer(
     const BootstrapSandbox* sandbox)
     : sandbox_(sandbox),
-      server_port_(MACH_PORT_NULL),
-      server_queue_(NULL),
-      server_source_(NULL),
-      did_forward_message_(false),
       sandbox_port_(MACH_PORT_NULL),
       compat_shim_(GetLaunchdCompatibilityShim()) {
 }
 
 LaunchdInterceptionServer::~LaunchdInterceptionServer() {
-  if (server_source_)
-    dispatch_release(server_source_);
-  if (server_queue_)
-    dispatch_release(server_queue_);
 }
 
 bool LaunchdInterceptionServer::Initialize() {
   mach_port_t task = mach_task_self();
   kern_return_t kr;
 
-  // Allocate a port for use as a new bootstrap port.
-  mach_port_t port;
-  if ((kr = mach_port_allocate(task, MACH_PORT_RIGHT_RECEIVE, &port)) !=
-          KERN_SUCCESS) {
-    MACH_LOG(ERROR, kr) << "Failed to allocate new bootstrap port.";
-    return false;
-  }
-  server_port_.reset(port);
-
-  // Allocate the message request and reply buffers.
-  const int kMachMsgMemoryFlags = VM_MAKE_TAG(VM_MEMORY_MACH_MSG) |
-                                  VM_FLAGS_ANYWHERE;
-  vm_address_t buffer = 0;
-
-  kr = vm_allocate(task, &buffer, kBufferSize, kMachMsgMemoryFlags);
-  if (kr != KERN_SUCCESS) {
-    MACH_LOG(ERROR, kr) << "Failed to allocate request buffer.";
-    return false;
-  }
-  request_buffer_.reset(buffer, kBufferSize);
-
-  kr = vm_allocate(task, &buffer, kBufferSize, kMachMsgMemoryFlags);
-  if (kr != KERN_SUCCESS) {
-    MACH_LOG(ERROR, kr) << "Failed to allocate reply buffer.";
-    return false;
-  }
-  reply_buffer_.reset(buffer, kBufferSize);
-
   // Allocate the dummy sandbox port.
+  mach_port_t port;
   if ((kr = mach_port_allocate(task, MACH_PORT_RIGHT_RECEIVE, &port)) !=
           KERN_SUCCESS) {
     MACH_LOG(ERROR, kr) << "Failed to allocate dummy sandbox port.";
@@ -83,114 +46,49 @@
   }
   sandbox_send_port_.reset(sandbox_port_);
 
-  // Set up the dispatch queue to service the bootstrap port.
-  // TODO(rsesek): Specify DISPATCH_QUEUE_SERIAL, in the 10.7 SDK. NULL means
-  // the same thing but is not symbolically clear.
-  server_queue_ = dispatch_queue_create(
-      "org.chromium.sandbox.LaunchdInterceptionServer", NULL);
-  server_source_ = dispatch_source_create(DISPATCH_SOURCE_TYPE_MACH_RECV,
-      server_port_.get(), 0, server_queue_);
-  dispatch_source_set_event_handler(server_source_, ^{ ReceiveMessage(); });
-  dispatch_resume(server_source_);
-
-  return true;
-}
-
-void LaunchdInterceptionServer::ReceiveMessage() {
-  const mach_msg_options_t kRcvOptions = MACH_RCV_MSG |
-      MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0) |
-      MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_AUDIT);
-
-  mach_msg_header_t* request =
-      reinterpret_cast<mach_msg_header_t*>(request_buffer_.address());
-  mach_msg_header_t* reply =
-      reinterpret_cast<mach_msg_header_t*>(reply_buffer_.address());
-
-  // Zero out the buffers from handling any previous message.
-  bzero(request, kBufferSize);
-  bzero(reply, kBufferSize);
-  did_forward_message_ = false;
-
-  // A Mach message server-once. The system library to run a message server
-  // cannot be used here, because some requests are conditionally forwarded
-  // to another server.
-  kern_return_t kr = mach_msg(request, kRcvOptions, 0, kBufferSize,
-      server_port_.get(), MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
-  if (kr != KERN_SUCCESS) {
-    MACH_LOG(ERROR, kr) << "Unable to receive message.";
-    return;
-  }
-
-  // Set up a reply message in case it will be used.
-  reply->msgh_bits = MACH_MSGH_BITS_REMOTE(reply->msgh_bits);
-  // Since mach_msg will automatically swap the request and reply ports,
-  // undo that.
-  reply->msgh_remote_port = request->msgh_remote_port;
-  reply->msgh_local_port = MACH_PORT_NULL;
-  // MIG servers simply add 100 to the request ID to generate the reply ID.
-  reply->msgh_id = request->msgh_id + 100;
-
-  // Process the message.
-  DemuxMessage(request, reply);
-
-  // Free any descriptors in the message body. If the message was forwarded,
-  // any descriptors would have been moved out of the process on send. If the
-  // forwarded message was sent from the process hosting this sandbox server,
-  // destroying the message could also destroy rights held outside the scope of
-  // this message server.
-  if (!did_forward_message_) {
-    mach_msg_destroy(request);
-    mach_msg_destroy(reply);
-  }
+  message_server_.reset(new MachMessageServer(this, kBufferSize));
+  return message_server_->Initialize();
 }
 
 void LaunchdInterceptionServer::DemuxMessage(mach_msg_header_t* request,
                                              mach_msg_header_t* reply) {
   VLOG(3) << "Incoming message #" << request->msgh_id;
 
-  // Get the PID of the task that sent this request. This requires getting at
-  // the trailer of the message, from the header.
-  mach_msg_audit_trailer_t* trailer =
-      reinterpret_cast<mach_msg_audit_trailer_t*>(
-          reinterpret_cast<vm_address_t>(request) +
-              round_msg(request->msgh_size));
-  // TODO(rsesek): In the 10.7 SDK, there's audit_token_to_pid().
-  pid_t sender_pid;
-  audit_token_to_au32(trailer->msgh_audit,
-      NULL, NULL, NULL, NULL, NULL, &sender_pid, NULL, NULL);
-
-  if (sandbox_->PolicyForProcess(sender_pid) == NULL) {
+  pid_t sender_pid = message_server_->GetMessageSenderPID(request);
+  const BootstrapSandboxPolicy* policy =
+      sandbox_->PolicyForProcess(sender_pid);
+  if (policy == NULL) {
     // No sandbox policy is in place for the sender of this message, which
     // means it is from the sandbox host process or an unsandboxed child.
     VLOG(3) << "Message from pid " << sender_pid << " forwarded to launchd";
-    ForwardMessage(request, reply);
+    ForwardMessage(request);
     return;
   }
 
   if (request->msgh_id == compat_shim_.msg_id_look_up2) {
     // Filter messages sent via bootstrap_look_up to enforce the sandbox policy
     // over the bootstrap namespace.
-    HandleLookUp(request, reply, sender_pid);
+    HandleLookUp(request, reply, policy);
   } else if (request->msgh_id == compat_shim_.msg_id_swap_integer) {
     // Ensure that any vproc_swap_integer requests are safe.
-    HandleSwapInteger(request, reply, sender_pid);
+    HandleSwapInteger(request, reply);
   } else {
     // All other messages are not permitted.
     VLOG(1) << "Rejecting unhandled message #" << request->msgh_id;
-    RejectMessage(request, reply, MIG_REMOTE_ERROR);
+    message_server_->RejectMessage(reply, MIG_REMOTE_ERROR);
   }
 }
 
-void LaunchdInterceptionServer::HandleLookUp(mach_msg_header_t* request,
-                                             mach_msg_header_t* reply,
-                                             pid_t sender_pid) {
+void LaunchdInterceptionServer::HandleLookUp(
+    mach_msg_header_t* request,
+    mach_msg_header_t* reply,
+    const BootstrapSandboxPolicy* policy) {
   const std::string request_service_name(
       compat_shim_.look_up2_get_request_name(request));
   VLOG(2) << "Incoming look_up2 request for " << request_service_name;
 
-  // Find the Rule for this service. If one is not found, use
-  // a safe default, POLICY_DENY_ERROR.
-  const BootstrapSandboxPolicy* policy = sandbox_->PolicyForProcess(sender_pid);
+  // Find the Rule for this service. If a named rule is not found, use the
+  // default specified by the policy.
   const BootstrapSandboxPolicy::NamedRules::const_iterator it =
       policy->rules.find(request_service_name);
   Rule rule(policy->default_rule);
@@ -201,13 +99,13 @@
     // This service is explicitly allowed, so this message will not be
     // intercepted by the sandbox.
     VLOG(1) << "Permitting and forwarding look_up2: " << request_service_name;
-    ForwardMessage(request, reply);
+    ForwardMessage(request);
   } else if (rule.result == POLICY_DENY_ERROR) {
     // The child is not permitted to look up this service. Send a MIG error
     // reply to the client. Returning a NULL or unserviced port for a look up
     // can cause clients to crash or hang.
     VLOG(1) << "Denying look_up2 with MIG error: " << request_service_name;
-    RejectMessage(request, reply, BOOTSTRAP_UNKNOWN_SERVICE);
+    message_server_->RejectMessage(reply, BOOTSTRAP_UNKNOWN_SERVICE);
   } else if (rule.result == POLICY_DENY_DUMMY_PORT ||
              rule.result == POLICY_SUBSTITUTE_PORT) {
     // The policy result is to deny access to the real service port, replying
@@ -227,7 +125,7 @@
     // message so that it is not destroyed at the end of ReceiveMessage. The
     // above-inserted right has been moved out of the process, and destroying
     // the message will unref yet another right.
-    if (SendReply(reply))
+    if (message_server_->SendReply(reply))
       compat_shim_.look_up2_fill_reply(reply, MACH_PORT_NULL);
   } else {
     NOTREACHED();
@@ -235,53 +133,20 @@
 }
 
 void LaunchdInterceptionServer::HandleSwapInteger(mach_msg_header_t* request,
-                                                  mach_msg_header_t* reply,
-                                                  pid_t sender_pid) {
+                                                  mach_msg_header_t* reply) {
   // Only allow getting information out of launchd. Do not allow setting
   // values. Two commonly observed values that are retrieved are
   // VPROC_GSK_MGR_PID and VPROC_GSK_TRANSACTIONS_ENABLED.
   if (compat_shim_.swap_integer_is_get_only(request)) {
     VLOG(2) << "Forwarding vproc swap_integer message.";
-    ForwardMessage(request, reply);
+    ForwardMessage(request);
   } else {
     VLOG(2) << "Rejecting non-read-only swap_integer message.";
-    RejectMessage(request, reply, BOOTSTRAP_NOT_PRIVILEGED);
+    message_server_->RejectMessage(reply, BOOTSTRAP_NOT_PRIVILEGED);
   }
 }
-
-bool LaunchdInterceptionServer::SendReply(mach_msg_header_t* reply) {
-  kern_return_t kr = mach_msg(reply, MACH_SEND_MSG, reply->msgh_size, 0,
-      MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
-  MACH_LOG_IF(ERROR, kr != KERN_SUCCESS, kr)
-      << "Unable to send intercepted reply message.";
-  return kr == KERN_SUCCESS;
-}
-
-void LaunchdInterceptionServer::ForwardMessage(mach_msg_header_t* request,
-                                               mach_msg_header_t* reply) {
-  request->msgh_local_port = request->msgh_remote_port;
-  request->msgh_remote_port = sandbox_->real_bootstrap_port();
-  // Preserve the msgh_bits that do not deal with the local and remote ports.
-  request->msgh_bits = (request->msgh_bits & ~MACH_MSGH_BITS_PORTS_MASK) |
-      MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, MACH_MSG_TYPE_MOVE_SEND_ONCE);
-  kern_return_t kr = mach_msg_send(request);
-  if (kr == KERN_SUCCESS) {
-    did_forward_message_ = true;
-  } else {
-    MACH_LOG(ERROR, kr) << "Unable to forward message to the real launchd.";
-  }
-}
-
-void LaunchdInterceptionServer::RejectMessage(mach_msg_header_t* request,
-                                              mach_msg_header_t* reply,
-                                              int error_code) {
-  mig_reply_error_t* error_reply = reinterpret_cast<mig_reply_error_t*>(reply);
-  error_reply->Head.msgh_size = sizeof(mig_reply_error_t);
-  error_reply->Head.msgh_bits =
-      MACH_MSGH_BITS_REMOTE(MACH_MSG_TYPE_MOVE_SEND_ONCE);
-  error_reply->NDR = NDR_record;
-  error_reply->RetCode = error_code;
-  SendReply(&error_reply->Head);
+void LaunchdInterceptionServer::ForwardMessage(mach_msg_header_t* request) {
+  message_server_->ForwardMessage(request, sandbox_->real_bootstrap_port());
 }
 
 }  // namespace sandbox
diff --git a/sandbox/mac/launchd_interception_server.h b/sandbox/mac/launchd_interception_server.h
index 1176533..2e80fec 100644
--- a/sandbox/mac/launchd_interception_server.h
+++ b/sandbox/mac/launchd_interception_server.h
@@ -9,81 +9,55 @@
 #include <mach/mach.h>
 
 #include "base/mac/scoped_mach_port.h"
-#include "base/mac/scoped_mach_vm.h"
+#include "base/memory/scoped_ptr.h"
+#include "sandbox/mac/mach_message_server.h"
 #include "sandbox/mac/os_compatibility.h"
 
 namespace sandbox {
 
 class BootstrapSandbox;
+struct BootstrapSandboxPolicy;
 
 // This class is used to run a Mach IPC message server. This server can
 // hold the receive right for a bootstrap_port of a process, and it filters
 // a subset of the launchd/bootstrap IPC call set for sandboxing. It permits
 // or rejects requests based on the per-process policy specified in the
 // BootstrapSandbox.
-class LaunchdInterceptionServer {
+class LaunchdInterceptionServer : public MessageDemuxer {
  public:
   explicit LaunchdInterceptionServer(const BootstrapSandbox* sandbox);
-  ~LaunchdInterceptionServer();
+  virtual ~LaunchdInterceptionServer();
 
   // Initializes the class and starts running the message server.
   bool Initialize();
 
-  mach_port_t server_port() const { return server_port_.get(); }
+  // MessageDemuxer:
+  virtual void DemuxMessage(mach_msg_header_t* request,
+                            mach_msg_header_t* reply) OVERRIDE;
+
+  mach_port_t server_port() const { return message_server_->server_port(); }
 
  private:
-  // Event handler for the |server_source_| that reads a message from the queue
-  // and processes it.
-  void ReceiveMessage();
-
-  // Decodes a message header and handles it by either servicing the request
-  // itself, forwarding the message on to the real launchd, or rejecting the
-  // message with an error.
-  void DemuxMessage(mach_msg_header_t* request, mach_msg_header_t* reply);
-
   // Given a look_up2 request message, this looks up the appropriate sandbox
   // policy for the service name then formulates and sends the reply message.
   void HandleLookUp(mach_msg_header_t* request,
                     mach_msg_header_t* reply,
-                    pid_t sender_pid);
+                    const BootstrapSandboxPolicy* policy);
 
   // Given a swap_integer request message, this verifies that it is safe, and
   // if so, forwards it on to launchd for servicing. If the request is unsafe,
   // it replies with an error.
   void HandleSwapInteger(mach_msg_header_t* request,
-                         mach_msg_header_t* reply,
-                         pid_t sender_pid);
-
-  // Sends a reply message. Returns true if the message was sent successfully.
-  bool SendReply(mach_msg_header_t* reply);
+                         mach_msg_header_t* reply);
 
   // Forwards the original |request| on to real bootstrap server for handling.
-  void ForwardMessage(mach_msg_header_t* request, mach_msg_header_t* reply);
-
-  // Replies to the message with the specified |error_code| as a MIG
-  // error_reply RetCode.
-  void RejectMessage(mach_msg_header_t* request,
-                     mach_msg_header_t* reply,
-                     int error_code);
+  void ForwardMessage(mach_msg_header_t* request);
 
   // The sandbox for which this message server is running.
   const BootstrapSandbox* sandbox_;
 
-  // The Mach port on which the server is receiving requests.
-  base::mac::ScopedMachReceiveRight server_port_;
-
-  // The dispatch queue used to service the server_source_.
-  dispatch_queue_t server_queue_;
-
-  // A MACH_RECV dispatch source for the server_port_.
-  dispatch_source_t server_source_;
-
-  // Request and reply buffers used in ReceiveMessage.
-  base::mac::ScopedMachVM request_buffer_;
-  base::mac::ScopedMachVM reply_buffer_;
-
-  // Whether or not ForwardMessage() was called during ReceiveMessage().
-  bool did_forward_message_;
+  // The Mach IPC server.
+  scoped_ptr<MachMessageServer> message_server_;
 
   // The Mach port handed out in reply to denied look up requests. All denied
   // requests share the same port, though nothing reads messages from it.
diff --git a/sandbox/mac/mach_message_server.cc b/sandbox/mac/mach_message_server.cc
new file mode 100644
index 0000000..9a10121
--- /dev/null
+++ b/sandbox/mac/mach_message_server.cc
@@ -0,0 +1,180 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/mac/mach_message_server.h"
+
+#include <bsm/libbsm.h>
+#include <servers/bootstrap.h>
+
+#include <string>
+
+#include "base/logging.h"
+#include "base/mac/mach_logging.h"
+#include "base/strings/stringprintf.h"
+
+namespace sandbox {
+
+MachMessageServer::MachMessageServer(
+    MessageDemuxer* demuxer,
+    mach_msg_size_t buffer_size)
+    : demuxer_(demuxer),
+      server_port_(MACH_PORT_NULL),
+      server_queue_(NULL),
+      server_source_(NULL),
+      buffer_size_(
+          mach_vm_round_page(buffer_size + sizeof(mach_msg_audit_trailer_t))),
+      did_forward_message_(false) {
+  DCHECK(demuxer_);
+}
+
+MachMessageServer::~MachMessageServer() {
+  if (server_source_)
+    dispatch_release(server_source_);
+  if (server_queue_)
+    dispatch_release(server_queue_);
+}
+
+bool MachMessageServer::Initialize() {
+  mach_port_t task = mach_task_self();
+  kern_return_t kr;
+
+  // Allocate a port for use as a new server port.
+  mach_port_t port;
+  if ((kr = mach_port_allocate(task, MACH_PORT_RIGHT_RECEIVE, &port)) !=
+          KERN_SUCCESS) {
+    MACH_LOG(ERROR, kr) << "Failed to allocate new server port.";
+    return false;
+  }
+  server_port_.reset(port);
+
+  // Allocate the message request and reply buffers.
+  const int kMachMsgMemoryFlags = VM_MAKE_TAG(VM_MEMORY_MACH_MSG) |
+                                  VM_FLAGS_ANYWHERE;
+  vm_address_t buffer = 0;
+
+  kr = vm_allocate(task, &buffer, buffer_size_, kMachMsgMemoryFlags);
+  if (kr != KERN_SUCCESS) {
+    MACH_LOG(ERROR, kr) << "Failed to allocate request buffer.";
+    return false;
+  }
+  request_buffer_.reset(buffer, buffer_size_);
+
+  kr = vm_allocate(task, &buffer, buffer_size_, kMachMsgMemoryFlags);
+  if (kr != KERN_SUCCESS) {
+    MACH_LOG(ERROR, kr) << "Failed to allocate reply buffer.";
+    return false;
+  }
+  reply_buffer_.reset(buffer, buffer_size_);
+
+  // Set up the dispatch queue to service the bootstrap port.
+  // TODO(rsesek): Specify DISPATCH_QUEUE_SERIAL, in the 10.7 SDK. NULL means
+  // the same thing but is not symbolically clear.
+  std::string label = base::StringPrintf(
+      "org.chromium.sandbox.MachMessageServer.%p", demuxer_);
+  server_queue_ = dispatch_queue_create(label.c_str(), NULL);
+  server_source_ = dispatch_source_create(DISPATCH_SOURCE_TYPE_MACH_RECV,
+      server_port_.get(), 0, server_queue_);
+  dispatch_source_set_event_handler(server_source_, ^{ ReceiveMessage(); });
+  dispatch_resume(server_source_);
+
+  return true;
+}
+
+pid_t MachMessageServer::GetMessageSenderPID(mach_msg_header_t* request) {
+  // Get the PID of the task that sent this request. This requires getting at
+  // the trailer of the message, from the header.
+  mach_msg_audit_trailer_t* trailer =
+      reinterpret_cast<mach_msg_audit_trailer_t*>(
+          reinterpret_cast<vm_address_t>(request) +
+              round_msg(request->msgh_size));
+  // TODO(rsesek): In the 10.7 SDK, there's audit_token_to_pid().
+  pid_t sender_pid;
+  audit_token_to_au32(trailer->msgh_audit,
+      NULL, NULL, NULL, NULL, NULL, &sender_pid, NULL, NULL);
+  return sender_pid;
+}
+
+bool MachMessageServer::SendReply(mach_msg_header_t* reply) {
+  kern_return_t kr = mach_msg(reply, MACH_SEND_MSG, reply->msgh_size, 0,
+      MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
+  MACH_LOG_IF(ERROR, kr != KERN_SUCCESS, kr)
+      << "Unable to send intercepted reply message.";
+  return kr == KERN_SUCCESS;
+}
+
+void MachMessageServer::ForwardMessage(mach_msg_header_t* request,
+                                       mach_port_t destination) {
+  request->msgh_local_port = request->msgh_remote_port;
+  request->msgh_remote_port = destination;
+  // Preserve the msgh_bits that do not deal with the local and remote ports.
+  request->msgh_bits = (request->msgh_bits & ~MACH_MSGH_BITS_PORTS_MASK) |
+      MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, MACH_MSG_TYPE_MOVE_SEND_ONCE);
+  kern_return_t kr = mach_msg_send(request);
+  if (kr == KERN_SUCCESS) {
+    did_forward_message_ = true;
+  } else {
+    MACH_LOG(ERROR, kr) << "Unable to forward message to the real launchd.";
+  }
+}
+
+void MachMessageServer::RejectMessage(mach_msg_header_t* reply,
+                                      int error_code) {
+  mig_reply_error_t* error_reply = reinterpret_cast<mig_reply_error_t*>(reply);
+  error_reply->Head.msgh_size = sizeof(mig_reply_error_t);
+  error_reply->Head.msgh_bits =
+      MACH_MSGH_BITS_REMOTE(MACH_MSG_TYPE_MOVE_SEND_ONCE);
+  error_reply->NDR = NDR_record;
+  error_reply->RetCode = error_code;
+  SendReply(&error_reply->Head);
+}
+
+void MachMessageServer::ReceiveMessage() {
+  const mach_msg_options_t kRcvOptions = MACH_RCV_MSG |
+      MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0) |
+      MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_AUDIT);
+
+  mach_msg_header_t* request =
+      reinterpret_cast<mach_msg_header_t*>(request_buffer_.address());
+  mach_msg_header_t* reply =
+      reinterpret_cast<mach_msg_header_t*>(reply_buffer_.address());
+
+  // Zero out the buffers from handling any previous message.
+  bzero(request, buffer_size_);
+  bzero(reply, buffer_size_);
+  did_forward_message_ = false;
+
+  // A Mach message server-once. The system library to run a message server
+  // cannot be used here, because some requests are conditionally forwarded
+  // to another server.
+  kern_return_t kr = mach_msg(request, kRcvOptions, 0, buffer_size_,
+      server_port_.get(), MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
+  if (kr != KERN_SUCCESS) {
+    MACH_LOG(ERROR, kr) << "Unable to receive message.";
+    return;
+  }
+
+  // Set up a reply message in case it will be used.
+  reply->msgh_bits = MACH_MSGH_BITS_REMOTE(reply->msgh_bits);
+  // Since mach_msg will automatically swap the request and reply ports,
+  // undo that.
+  reply->msgh_remote_port = request->msgh_remote_port;
+  reply->msgh_local_port = MACH_PORT_NULL;
+  // MIG servers simply add 100 to the request ID to generate the reply ID.
+  reply->msgh_id = request->msgh_id + 100;
+
+  // Process the message.
+  demuxer_->DemuxMessage(request, reply);
+
+  // Free any descriptors in the message body. If the message was forwarded,
+  // any descriptors would have been moved out of the process on send. If the
+  // forwarded message was sent from the process hosting this sandbox server,
+  // destroying the message could also destroy rights held outside the scope of
+  // this message server.
+  if (!did_forward_message_) {
+    mach_msg_destroy(request);
+    mach_msg_destroy(reply);
+  }
+}
+
+}  // namespace sandbox
diff --git a/sandbox/mac/mach_message_server.h b/sandbox/mac/mach_message_server.h
new file mode 100644
index 0000000..f37b4fc
--- /dev/null
+++ b/sandbox/mac/mach_message_server.h
@@ -0,0 +1,88 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_MAC_MACH_MESSAGE_SERVER_H_
+#define SANDBOX_MAC_MACH_MESSAGE_SERVER_H_
+
+#include <dispatch/dispatch.h>
+#include <mach/mach.h>
+
+#include "base/mac/scoped_mach_port.h"
+#include "base/mac/scoped_mach_vm.h"
+
+namespace sandbox {
+
+// A delegate interface for MachMessageServer that handles processing of
+// incoming intercepted IPC messages.
+class MessageDemuxer {
+ public:
+  // Handle a |request| message and optionally create a |reply|. Both message
+  // objects are owned by the server. Use the server's methods to send a
+  // reply message.
+  virtual void DemuxMessage(mach_msg_header_t* request,
+                            mach_msg_header_t* reply) = 0;
+
+ protected:
+  virtual ~MessageDemuxer() {}
+};
+
+// A Mach message server that operates a receive port. Messages are received
+// and then passed to the MessageDemuxer for handling. The Demuxer
+// can use the server class to send a reply, forward the message to a
+// different port, or reply to the message with a MIG error.
+class MachMessageServer {
+ public:
+  MachMessageServer(MessageDemuxer* demuxer, mach_msg_size_t buffer_size);
+  ~MachMessageServer();
+
+  // Initializes the class and starts running the message server. If this
+  // returns false, no other methods may be called on this class.
+  bool Initialize();
+
+  // Given a received request message, returns the PID of the sending process.
+  pid_t GetMessageSenderPID(mach_msg_header_t* request);
+
+  // Sends a reply message. Returns true if the message was sent successfully.
+  bool SendReply(mach_msg_header_t* reply);
+
+  // Forwards the original |request| to the |destination| for handling.
+  void ForwardMessage(mach_msg_header_t* request, mach_port_t destination);
+
+  // Replies to the message with the specified |error_code| as a MIG
+  // error_reply RetCode.
+  void RejectMessage(mach_msg_header_t* reply, int error_code);
+
+  mach_port_t server_port() const { return server_port_.get(); }
+
+ private:
+  // Event handler for the |server_source_| that reads a message from the queue
+  // and processes it.
+  void ReceiveMessage();
+
+  // The demuxer delegate. Weak.
+  MessageDemuxer* demuxer_;
+
+  // The Mach port on which the server is receiving requests.
+  base::mac::ScopedMachReceiveRight server_port_;
+
+  // The dispatch queue used to service the server_source_.
+  dispatch_queue_t server_queue_;
+
+  // A MACH_RECV dispatch source for the server_port_.
+  dispatch_source_t server_source_;
+
+  // The size of the two message buffers below.
+  const mach_msg_size_t buffer_size_;
+
+  // Request and reply buffers used in ReceiveMessage.
+  base::mac::ScopedMachVM request_buffer_;
+  base::mac::ScopedMachVM reply_buffer_;
+
+  // Whether or not ForwardMessage() was called during ReceiveMessage().
+  bool did_forward_message_;
+};
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_MAC_MACH_MESSAGE_SERVER_H_
diff --git a/sandbox/mac/os_compatibility.cc b/sandbox/mac/os_compatibility.cc
index be0ca3e..4485006 100644
--- a/sandbox/mac/os_compatibility.cc
+++ b/sandbox/mac/os_compatibility.cc
@@ -112,7 +112,7 @@
     shim.look_up2_get_request_name =
         &LaunchdLookUp2GetRequestName<look_up2_request_10_6>;
   } else if (base::mac::IsOSLionOrLater() &&
-             !base::mac::IsOSLaterThanMavericks_DontCallThis()) {
+             !base::mac::IsOSYosemiteOrLater()) {
     shim.look_up2_get_request_name =
         &LaunchdLookUp2GetRequestName<look_up2_request_10_7>;
   } else {
diff --git a/sandbox/mac/sandbox_mac.gypi b/sandbox/mac/sandbox_mac.gypi
index 1824127..36d6901 100644
--- a/sandbox/mac/sandbox_mac.gypi
+++ b/sandbox/mac/sandbox_mac.gypi
@@ -12,16 +12,20 @@
         'bootstrap_sandbox.h',
         'launchd_interception_server.cc',
         'launchd_interception_server.h',
-        'policy.cc',
-        'policy.h',
+        'mach_message_server.cc',
+        'mach_message_server.h',
         'os_compatibility.cc',
         'os_compatibility.h',
+        'policy.cc',
+        'policy.h',
+        'xpc.h',
       ],
       'dependencies': [
         '../base/base.gyp:base',
       ],
       'include_dirs': [
         '..',
+        '<(SHARED_INTERMEDIATE_DIR)',
       ],
       'defines': [
         'SANDBOX_IMPLEMENTATION',
@@ -31,6 +35,43 @@
           '$(SDKROOT)/usr/lib/libbsm.dylib',
         ],
       },
+      'actions': [
+        {
+          'variables': {
+            'generate_stubs_script': '../tools/generate_stubs/generate_stubs.py',
+            'generate_stubs_header_path': 'xpc_stubs_header.fragment',
+            'generate_stubs_sig_public_path': 'xpc_stubs.sig',
+            'generate_stubs_sig_private_path': 'xpc_private_stubs.sig',
+            'generate_stubs_project': 'sandbox/mac',
+            'generate_stubs_output_stem': 'xpc_stubs',
+          },
+          'action_name': 'generate_stubs',
+          'inputs': [
+            '<(generate_stubs_script)',
+            '<(generate_stubs_header_path)',
+            '<(generate_stubs_sig_public_path)',
+            '<(generate_stubs_sig_private_path)',
+          ],
+          'outputs': [
+            '<(INTERMEDIATE_DIR)/<(generate_stubs_output_stem).cc',
+            '<(SHARED_INTERMEDIATE_DIR)/<(generate_stubs_project)/<(generate_stubs_output_stem).h',
+          ],
+          'action': [
+            'python',
+            '<(generate_stubs_script)',
+            '-i', '<(INTERMEDIATE_DIR)',
+            '-o', '<(SHARED_INTERMEDIATE_DIR)/<(generate_stubs_project)',
+            '-t', 'posix_stubs',
+            '-e', '<(generate_stubs_header_path)',
+            '-s', '<(generate_stubs_output_stem)',
+            '-p', '<(generate_stubs_project)',
+            '<(generate_stubs_sig_public_path)',
+            '<(generate_stubs_sig_private_path)',
+          ],
+          'process_outputs_as_sources': 1,
+          'message': 'Generating XPC stubs for 10.6 compatability.',
+        },
+      ],
     },
     {
       'target_name': 'sandbox_mac_unittests',
diff --git a/sandbox/mac/xpc.h b/sandbox/mac/xpc.h
new file mode 100644
index 0000000..1cbe9ca
--- /dev/null
+++ b/sandbox/mac/xpc.h
@@ -0,0 +1,40 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file provides forward declarations for XPC symbols that are not
+// present in the 10.6 SDK. It uses generate_stubs to produce code to
+// dynamically load the libxpc.dylib library and set up a stub table, with
+// the same names as the real XPC functions.
+
+#ifndef SANDBOX_MAC_XPC_H_
+#define SANDBOX_MAC_XPC_H_
+
+#include <mach/mach.h>
+
+// C++ library loader.
+#include "sandbox/mac/xpc_stubs.h"
+
+// Declares XPC object types. This includes <xpc/xpc.h> if available.
+#include "sandbox/mac/xpc_stubs_header.fragment"
+
+#if !defined(MAC_OS_X_VERSION_10_7) || \
+    MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7
+
+extern "C" {
+// Signatures for XPC public functions that are loaded by xpc_stubs.h.
+#include "sandbox/mac/xpc_stubs.sig"
+// Signatures for private XPC functions.
+#include "sandbox/mac/xpc_private_stubs.sig"
+}  // extern "C"
+
+#else
+
+// Signatures for private XPC functions.
+extern "C" {
+#include "sandbox/mac/xpc_private_stubs.sig"
+}  // extern "C"
+
+#endif
+
+#endif  // SANDBOX_MAC_XPC_H_
diff --git a/sandbox/mac/xpc_private_stubs.sig b/sandbox/mac/xpc_private_stubs.sig
new file mode 100644
index 0000000..33db194
--- /dev/null
+++ b/sandbox/mac/xpc_private_stubs.sig
@@ -0,0 +1,17 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file contains declarations of private XPC functions. This file is
+// used for both forward declarations of private symbols and to use with
+// tools/generate_stubs for creating a dynamic library loader.
+
+// Dictionary manipulation.
+void xpc_dictionary_set_mach_send(xpc_object_t dict, const char* name, mach_port_t port);
+
+// Pipe methods.
+xpc_pipe_t xpc_pipe_create_from_port(mach_port_t port, int flags);
+int xpc_pipe_receive(mach_port_t port, xpc_object_t* message);
+int xpc_pipe_routine(xpc_pipe_t pipe, xpc_object_t request, xpc_object_t* reply);
+int xpc_pipe_routine_reply(xpc_object_t reply);
+int xpc_pipe_routine_forward(xpc_pipe_t forward_to, xpc_object_t request);
diff --git a/sandbox/mac/xpc_stubs.sig b/sandbox/mac/xpc_stubs.sig
new file mode 100644
index 0000000..5020ffd
--- /dev/null
+++ b/sandbox/mac/xpc_stubs.sig
@@ -0,0 +1,16 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file contains declarations of public XPC functions used in the sandbox.
+// This file is used with tools/generate_stubs for creating a dynamic library
+// loader.
+
+// XPC object management.
+void xpc_release(xpc_object_t object);
+
+// Dictionary manipulation.
+const char* xpc_dictionary_get_string(xpc_object_t dictionary, const char* key);
+uint64_t xpc_dictionary_get_uint64(xpc_object_t dictionary, const char* key);
+void xpc_dictionary_set_int64(xpc_object_t dictionary, const char* key, int64_t value);
+xpc_object_t xpc_dictionary_create_reply(xpc_object_t request);
diff --git a/sandbox/mac/xpc_stubs_header.fragment b/sandbox/mac/xpc_stubs_header.fragment
new file mode 100644
index 0000000..a29907e
--- /dev/null
+++ b/sandbox/mac/xpc_stubs_header.fragment
@@ -0,0 +1,27 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_MAC_XPC_STUBS_HEADER_FRAGMENT_
+#define SANDBOX_MAC_XPC_STUBS_HEADER_FRAGMENT_
+
+// Declare or include public types.
+#if !defined(MAC_OS_X_VERSION_10_7) || \
+    MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7
+
+extern "C" {
+typedef void* xpc_object_t;
+}  // extern "C"
+
+#else
+
+#include <xpc/xpc.h>
+
+#endif
+
+// Declare private types.
+extern "C" {
+typedef struct _xpc_pipe_s* xpc_pipe_t;
+}  // extern "C"
+
+#endif  // SANDBOX_MAC_XPC_STUBS_HEADER_FRAGMENT_
diff --git a/sandbox/sandbox_services.target.darwin-arm.mk b/sandbox/sandbox_services.target.darwin-arm.mk
index f079c1d..0148b53 100644
--- a/sandbox/sandbox_services.target.darwin-arm.mk
+++ b/sandbox/sandbox_services.target.darwin-arm.mk
@@ -82,6 +82,7 @@
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DENABLE_WEBRTC=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
@@ -112,6 +113,7 @@
 # Include paths placed before CFLAGS/CPPFLAGS
 LOCAL_C_INCLUDES_Debug := \
 	$(gyp_shared_intermediate_dir)/shim_headers/ashmem/target \
+	$(gyp_shared_intermediate_dir) \
 	$(LOCAL_PATH)/sandbox \
 	$(LOCAL_PATH) \
 	$(PWD)/frameworks/wilhelm/include \
@@ -181,6 +183,7 @@
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DENABLE_WEBRTC=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
@@ -212,6 +215,7 @@
 # Include paths placed before CFLAGS/CPPFLAGS
 LOCAL_C_INCLUDES_Release := \
 	$(gyp_shared_intermediate_dir)/shim_headers/ashmem/target \
+	$(gyp_shared_intermediate_dir) \
 	$(LOCAL_PATH)/sandbox \
 	$(LOCAL_PATH) \
 	$(PWD)/frameworks/wilhelm/include \
diff --git a/sandbox/sandbox_services.target.darwin-arm64.mk b/sandbox/sandbox_services.target.darwin-arm64.mk
index 6337b1b..ce59907 100644
--- a/sandbox/sandbox_services.target.darwin-arm64.mk
+++ b/sandbox/sandbox_services.target.darwin-arm64.mk
@@ -72,6 +72,7 @@
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DENABLE_WEBRTC=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
@@ -102,6 +103,7 @@
 # Include paths placed before CFLAGS/CPPFLAGS
 LOCAL_C_INCLUDES_Debug := \
 	$(gyp_shared_intermediate_dir)/shim_headers/ashmem/target \
+	$(gyp_shared_intermediate_dir) \
 	$(LOCAL_PATH)/sandbox \
 	$(LOCAL_PATH) \
 	$(PWD)/frameworks/wilhelm/include \
@@ -160,6 +162,7 @@
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DENABLE_WEBRTC=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
@@ -191,6 +194,7 @@
 # Include paths placed before CFLAGS/CPPFLAGS
 LOCAL_C_INCLUDES_Release := \
 	$(gyp_shared_intermediate_dir)/shim_headers/ashmem/target \
+	$(gyp_shared_intermediate_dir) \
 	$(LOCAL_PATH)/sandbox \
 	$(LOCAL_PATH) \
 	$(PWD)/frameworks/wilhelm/include \
diff --git a/sandbox/sandbox_services.target.darwin-mips.mk b/sandbox/sandbox_services.target.darwin-mips.mk
index f188c24..c92d333 100644
--- a/sandbox/sandbox_services.target.darwin-mips.mk
+++ b/sandbox/sandbox_services.target.darwin-mips.mk
@@ -76,6 +76,7 @@
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DENABLE_WEBRTC=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
@@ -106,6 +107,7 @@
 # Include paths placed before CFLAGS/CPPFLAGS
 LOCAL_C_INCLUDES_Debug := \
 	$(gyp_shared_intermediate_dir)/shim_headers/ashmem/target \
+	$(gyp_shared_intermediate_dir) \
 	$(LOCAL_PATH)/sandbox \
 	$(LOCAL_PATH) \
 	$(PWD)/frameworks/wilhelm/include \
@@ -169,6 +171,7 @@
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DENABLE_WEBRTC=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
@@ -200,6 +203,7 @@
 # Include paths placed before CFLAGS/CPPFLAGS
 LOCAL_C_INCLUDES_Release := \
 	$(gyp_shared_intermediate_dir)/shim_headers/ashmem/target \
+	$(gyp_shared_intermediate_dir) \
 	$(LOCAL_PATH)/sandbox \
 	$(LOCAL_PATH) \
 	$(PWD)/frameworks/wilhelm/include \
diff --git a/sandbox/sandbox_services.target.darwin-x86.mk b/sandbox/sandbox_services.target.darwin-x86.mk
index 9dcce10..330bd65 100644
--- a/sandbox/sandbox_services.target.darwin-x86.mk
+++ b/sandbox/sandbox_services.target.darwin-x86.mk
@@ -77,6 +77,7 @@
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DENABLE_WEBRTC=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
@@ -107,6 +108,7 @@
 # Include paths placed before CFLAGS/CPPFLAGS
 LOCAL_C_INCLUDES_Debug := \
 	$(gyp_shared_intermediate_dir)/shim_headers/ashmem/target \
+	$(gyp_shared_intermediate_dir) \
 	$(LOCAL_PATH)/sandbox \
 	$(LOCAL_PATH) \
 	$(PWD)/frameworks/wilhelm/include \
@@ -170,6 +172,7 @@
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DENABLE_WEBRTC=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
@@ -201,6 +204,7 @@
 # Include paths placed before CFLAGS/CPPFLAGS
 LOCAL_C_INCLUDES_Release := \
 	$(gyp_shared_intermediate_dir)/shim_headers/ashmem/target \
+	$(gyp_shared_intermediate_dir) \
 	$(LOCAL_PATH)/sandbox \
 	$(LOCAL_PATH) \
 	$(PWD)/frameworks/wilhelm/include \
diff --git a/sandbox/sandbox_services.target.darwin-x86_64.mk b/sandbox/sandbox_services.target.darwin-x86_64.mk
index 6d20bbd..525a2af 100644
--- a/sandbox/sandbox_services.target.darwin-x86_64.mk
+++ b/sandbox/sandbox_services.target.darwin-x86_64.mk
@@ -76,6 +76,7 @@
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DENABLE_WEBRTC=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
@@ -106,6 +107,7 @@
 # Include paths placed before CFLAGS/CPPFLAGS
 LOCAL_C_INCLUDES_Debug := \
 	$(gyp_shared_intermediate_dir)/shim_headers/ashmem/target \
+	$(gyp_shared_intermediate_dir) \
 	$(LOCAL_PATH)/sandbox \
 	$(LOCAL_PATH) \
 	$(PWD)/frameworks/wilhelm/include \
@@ -168,6 +170,7 @@
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DENABLE_WEBRTC=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
@@ -199,6 +202,7 @@
 # Include paths placed before CFLAGS/CPPFLAGS
 LOCAL_C_INCLUDES_Release := \
 	$(gyp_shared_intermediate_dir)/shim_headers/ashmem/target \
+	$(gyp_shared_intermediate_dir) \
 	$(LOCAL_PATH)/sandbox \
 	$(LOCAL_PATH) \
 	$(PWD)/frameworks/wilhelm/include \
diff --git a/sandbox/sandbox_services.target.linux-arm.mk b/sandbox/sandbox_services.target.linux-arm.mk
index f079c1d..0148b53 100644
--- a/sandbox/sandbox_services.target.linux-arm.mk
+++ b/sandbox/sandbox_services.target.linux-arm.mk
@@ -82,6 +82,7 @@
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DENABLE_WEBRTC=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
@@ -112,6 +113,7 @@
 # Include paths placed before CFLAGS/CPPFLAGS
 LOCAL_C_INCLUDES_Debug := \
 	$(gyp_shared_intermediate_dir)/shim_headers/ashmem/target \
+	$(gyp_shared_intermediate_dir) \
 	$(LOCAL_PATH)/sandbox \
 	$(LOCAL_PATH) \
 	$(PWD)/frameworks/wilhelm/include \
@@ -181,6 +183,7 @@
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DENABLE_WEBRTC=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
@@ -212,6 +215,7 @@
 # Include paths placed before CFLAGS/CPPFLAGS
 LOCAL_C_INCLUDES_Release := \
 	$(gyp_shared_intermediate_dir)/shim_headers/ashmem/target \
+	$(gyp_shared_intermediate_dir) \
 	$(LOCAL_PATH)/sandbox \
 	$(LOCAL_PATH) \
 	$(PWD)/frameworks/wilhelm/include \
diff --git a/sandbox/sandbox_services.target.linux-arm64.mk b/sandbox/sandbox_services.target.linux-arm64.mk
index 6337b1b..ce59907 100644
--- a/sandbox/sandbox_services.target.linux-arm64.mk
+++ b/sandbox/sandbox_services.target.linux-arm64.mk
@@ -72,6 +72,7 @@
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DENABLE_WEBRTC=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
@@ -102,6 +103,7 @@
 # Include paths placed before CFLAGS/CPPFLAGS
 LOCAL_C_INCLUDES_Debug := \
 	$(gyp_shared_intermediate_dir)/shim_headers/ashmem/target \
+	$(gyp_shared_intermediate_dir) \
 	$(LOCAL_PATH)/sandbox \
 	$(LOCAL_PATH) \
 	$(PWD)/frameworks/wilhelm/include \
@@ -160,6 +162,7 @@
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DENABLE_WEBRTC=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
@@ -191,6 +194,7 @@
 # Include paths placed before CFLAGS/CPPFLAGS
 LOCAL_C_INCLUDES_Release := \
 	$(gyp_shared_intermediate_dir)/shim_headers/ashmem/target \
+	$(gyp_shared_intermediate_dir) \
 	$(LOCAL_PATH)/sandbox \
 	$(LOCAL_PATH) \
 	$(PWD)/frameworks/wilhelm/include \
diff --git a/sandbox/sandbox_services.target.linux-mips.mk b/sandbox/sandbox_services.target.linux-mips.mk
index f188c24..c92d333 100644
--- a/sandbox/sandbox_services.target.linux-mips.mk
+++ b/sandbox/sandbox_services.target.linux-mips.mk
@@ -76,6 +76,7 @@
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DENABLE_WEBRTC=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
@@ -106,6 +107,7 @@
 # Include paths placed before CFLAGS/CPPFLAGS
 LOCAL_C_INCLUDES_Debug := \
 	$(gyp_shared_intermediate_dir)/shim_headers/ashmem/target \
+	$(gyp_shared_intermediate_dir) \
 	$(LOCAL_PATH)/sandbox \
 	$(LOCAL_PATH) \
 	$(PWD)/frameworks/wilhelm/include \
@@ -169,6 +171,7 @@
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DENABLE_WEBRTC=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
@@ -200,6 +203,7 @@
 # Include paths placed before CFLAGS/CPPFLAGS
 LOCAL_C_INCLUDES_Release := \
 	$(gyp_shared_intermediate_dir)/shim_headers/ashmem/target \
+	$(gyp_shared_intermediate_dir) \
 	$(LOCAL_PATH)/sandbox \
 	$(LOCAL_PATH) \
 	$(PWD)/frameworks/wilhelm/include \
diff --git a/sandbox/sandbox_services.target.linux-x86.mk b/sandbox/sandbox_services.target.linux-x86.mk
index 9dcce10..330bd65 100644
--- a/sandbox/sandbox_services.target.linux-x86.mk
+++ b/sandbox/sandbox_services.target.linux-x86.mk
@@ -77,6 +77,7 @@
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DENABLE_WEBRTC=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
@@ -107,6 +108,7 @@
 # Include paths placed before CFLAGS/CPPFLAGS
 LOCAL_C_INCLUDES_Debug := \
 	$(gyp_shared_intermediate_dir)/shim_headers/ashmem/target \
+	$(gyp_shared_intermediate_dir) \
 	$(LOCAL_PATH)/sandbox \
 	$(LOCAL_PATH) \
 	$(PWD)/frameworks/wilhelm/include \
@@ -170,6 +172,7 @@
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DENABLE_WEBRTC=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
@@ -201,6 +204,7 @@
 # Include paths placed before CFLAGS/CPPFLAGS
 LOCAL_C_INCLUDES_Release := \
 	$(gyp_shared_intermediate_dir)/shim_headers/ashmem/target \
+	$(gyp_shared_intermediate_dir) \
 	$(LOCAL_PATH)/sandbox \
 	$(LOCAL_PATH) \
 	$(PWD)/frameworks/wilhelm/include \
diff --git a/sandbox/sandbox_services.target.linux-x86_64.mk b/sandbox/sandbox_services.target.linux-x86_64.mk
index 6d20bbd..525a2af 100644
--- a/sandbox/sandbox_services.target.linux-x86_64.mk
+++ b/sandbox/sandbox_services.target.linux-x86_64.mk
@@ -76,6 +76,7 @@
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DENABLE_WEBRTC=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
@@ -106,6 +107,7 @@
 # Include paths placed before CFLAGS/CPPFLAGS
 LOCAL_C_INCLUDES_Debug := \
 	$(gyp_shared_intermediate_dir)/shim_headers/ashmem/target \
+	$(gyp_shared_intermediate_dir) \
 	$(LOCAL_PATH)/sandbox \
 	$(LOCAL_PATH) \
 	$(PWD)/frameworks/wilhelm/include \
@@ -168,6 +170,7 @@
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DENABLE_WEBRTC=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
@@ -199,6 +202,7 @@
 # Include paths placed before CFLAGS/CPPFLAGS
 LOCAL_C_INCLUDES_Release := \
 	$(gyp_shared_intermediate_dir)/shim_headers/ashmem/target \
+	$(gyp_shared_intermediate_dir) \
 	$(LOCAL_PATH)/sandbox \
 	$(LOCAL_PATH) \
 	$(PWD)/frameworks/wilhelm/include \
diff --git a/sandbox/sandbox_services_headers.target.darwin-arm.mk b/sandbox/sandbox_services_headers.target.darwin-arm.mk
index eb6a359..5c53c90 100644
--- a/sandbox/sandbox_services_headers.target.darwin-arm.mk
+++ b/sandbox/sandbox_services_headers.target.darwin-arm.mk
@@ -77,6 +77,7 @@
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DENABLE_WEBRTC=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
@@ -105,6 +106,7 @@
 
 # Include paths placed before CFLAGS/CPPFLAGS
 LOCAL_C_INCLUDES_Debug := \
+	$(gyp_shared_intermediate_dir) \
 	$(LOCAL_PATH)/sandbox \
 	$(PWD)/frameworks/wilhelm/include \
 	$(PWD)/bionic \
@@ -173,6 +175,7 @@
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DENABLE_WEBRTC=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
@@ -202,6 +205,7 @@
 
 # Include paths placed before CFLAGS/CPPFLAGS
 LOCAL_C_INCLUDES_Release := \
+	$(gyp_shared_intermediate_dir) \
 	$(LOCAL_PATH)/sandbox \
 	$(PWD)/frameworks/wilhelm/include \
 	$(PWD)/bionic \
diff --git a/sandbox/sandbox_services_headers.target.darwin-x86.mk b/sandbox/sandbox_services_headers.target.darwin-x86.mk
index 71f95e4..4ed441e 100644
--- a/sandbox/sandbox_services_headers.target.darwin-x86.mk
+++ b/sandbox/sandbox_services_headers.target.darwin-x86.mk
@@ -72,6 +72,7 @@
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DENABLE_WEBRTC=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
@@ -100,6 +101,7 @@
 
 # Include paths placed before CFLAGS/CPPFLAGS
 LOCAL_C_INCLUDES_Debug := \
+	$(gyp_shared_intermediate_dir) \
 	$(LOCAL_PATH)/sandbox \
 	$(PWD)/frameworks/wilhelm/include \
 	$(PWD)/bionic \
@@ -162,6 +164,7 @@
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DENABLE_WEBRTC=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
@@ -191,6 +194,7 @@
 
 # Include paths placed before CFLAGS/CPPFLAGS
 LOCAL_C_INCLUDES_Release := \
+	$(gyp_shared_intermediate_dir) \
 	$(LOCAL_PATH)/sandbox \
 	$(PWD)/frameworks/wilhelm/include \
 	$(PWD)/bionic \
diff --git a/sandbox/sandbox_services_headers.target.darwin-x86_64.mk b/sandbox/sandbox_services_headers.target.darwin-x86_64.mk
index 80a1ea1..ab9b686 100644
--- a/sandbox/sandbox_services_headers.target.darwin-x86_64.mk
+++ b/sandbox/sandbox_services_headers.target.darwin-x86_64.mk
@@ -71,6 +71,7 @@
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DENABLE_WEBRTC=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
@@ -99,6 +100,7 @@
 
 # Include paths placed before CFLAGS/CPPFLAGS
 LOCAL_C_INCLUDES_Debug := \
+	$(gyp_shared_intermediate_dir) \
 	$(LOCAL_PATH)/sandbox \
 	$(PWD)/frameworks/wilhelm/include \
 	$(PWD)/bionic \
@@ -160,6 +162,7 @@
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DENABLE_WEBRTC=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
@@ -189,6 +192,7 @@
 
 # Include paths placed before CFLAGS/CPPFLAGS
 LOCAL_C_INCLUDES_Release := \
+	$(gyp_shared_intermediate_dir) \
 	$(LOCAL_PATH)/sandbox \
 	$(PWD)/frameworks/wilhelm/include \
 	$(PWD)/bionic \
diff --git a/sandbox/sandbox_services_headers.target.linux-arm.mk b/sandbox/sandbox_services_headers.target.linux-arm.mk
index eb6a359..5c53c90 100644
--- a/sandbox/sandbox_services_headers.target.linux-arm.mk
+++ b/sandbox/sandbox_services_headers.target.linux-arm.mk
@@ -77,6 +77,7 @@
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DENABLE_WEBRTC=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
@@ -105,6 +106,7 @@
 
 # Include paths placed before CFLAGS/CPPFLAGS
 LOCAL_C_INCLUDES_Debug := \
+	$(gyp_shared_intermediate_dir) \
 	$(LOCAL_PATH)/sandbox \
 	$(PWD)/frameworks/wilhelm/include \
 	$(PWD)/bionic \
@@ -173,6 +175,7 @@
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DENABLE_WEBRTC=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
@@ -202,6 +205,7 @@
 
 # Include paths placed before CFLAGS/CPPFLAGS
 LOCAL_C_INCLUDES_Release := \
+	$(gyp_shared_intermediate_dir) \
 	$(LOCAL_PATH)/sandbox \
 	$(PWD)/frameworks/wilhelm/include \
 	$(PWD)/bionic \
diff --git a/sandbox/sandbox_services_headers.target.linux-x86.mk b/sandbox/sandbox_services_headers.target.linux-x86.mk
index 71f95e4..4ed441e 100644
--- a/sandbox/sandbox_services_headers.target.linux-x86.mk
+++ b/sandbox/sandbox_services_headers.target.linux-x86.mk
@@ -72,6 +72,7 @@
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DENABLE_WEBRTC=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
@@ -100,6 +101,7 @@
 
 # Include paths placed before CFLAGS/CPPFLAGS
 LOCAL_C_INCLUDES_Debug := \
+	$(gyp_shared_intermediate_dir) \
 	$(LOCAL_PATH)/sandbox \
 	$(PWD)/frameworks/wilhelm/include \
 	$(PWD)/bionic \
@@ -162,6 +164,7 @@
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DENABLE_WEBRTC=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
@@ -191,6 +194,7 @@
 
 # Include paths placed before CFLAGS/CPPFLAGS
 LOCAL_C_INCLUDES_Release := \
+	$(gyp_shared_intermediate_dir) \
 	$(LOCAL_PATH)/sandbox \
 	$(PWD)/frameworks/wilhelm/include \
 	$(PWD)/bionic \
diff --git a/sandbox/sandbox_services_headers.target.linux-x86_64.mk b/sandbox/sandbox_services_headers.target.linux-x86_64.mk
index 80a1ea1..ab9b686 100644
--- a/sandbox/sandbox_services_headers.target.linux-x86_64.mk
+++ b/sandbox/sandbox_services_headers.target.linux-x86_64.mk
@@ -71,6 +71,7 @@
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DENABLE_WEBRTC=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
@@ -99,6 +100,7 @@
 
 # Include paths placed before CFLAGS/CPPFLAGS
 LOCAL_C_INCLUDES_Debug := \
+	$(gyp_shared_intermediate_dir) \
 	$(LOCAL_PATH)/sandbox \
 	$(PWD)/frameworks/wilhelm/include \
 	$(PWD)/bionic \
@@ -160,6 +162,7 @@
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DENABLE_WEBRTC=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
@@ -189,6 +192,7 @@
 
 # Include paths placed before CFLAGS/CPPFLAGS
 LOCAL_C_INCLUDES_Release := \
+	$(gyp_shared_intermediate_dir) \
 	$(LOCAL_PATH)/sandbox \
 	$(PWD)/frameworks/wilhelm/include \
 	$(PWD)/bionic \
diff --git a/sandbox/seccomp_bpf.target.darwin-arm.mk b/sandbox/seccomp_bpf.target.darwin-arm.mk
index 42ca308..044e15f 100644
--- a/sandbox/seccomp_bpf.target.darwin-arm.mk
+++ b/sandbox/seccomp_bpf.target.darwin-arm.mk
@@ -88,6 +88,7 @@
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DENABLE_WEBRTC=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
@@ -118,6 +119,7 @@
 # Include paths placed before CFLAGS/CPPFLAGS
 LOCAL_C_INCLUDES_Debug := \
 	$(gyp_shared_intermediate_dir)/shim_headers/ashmem/target \
+	$(gyp_shared_intermediate_dir) \
 	$(LOCAL_PATH) \
 	$(PWD)/frameworks/wilhelm/include \
 	$(PWD)/bionic \
@@ -186,6 +188,7 @@
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DENABLE_WEBRTC=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
@@ -217,6 +220,7 @@
 # Include paths placed before CFLAGS/CPPFLAGS
 LOCAL_C_INCLUDES_Release := \
 	$(gyp_shared_intermediate_dir)/shim_headers/ashmem/target \
+	$(gyp_shared_intermediate_dir) \
 	$(LOCAL_PATH) \
 	$(PWD)/frameworks/wilhelm/include \
 	$(PWD)/bionic \
diff --git a/sandbox/seccomp_bpf.target.darwin-x86.mk b/sandbox/seccomp_bpf.target.darwin-x86.mk
index f807852..00e9eb4 100644
--- a/sandbox/seccomp_bpf.target.darwin-x86.mk
+++ b/sandbox/seccomp_bpf.target.darwin-x86.mk
@@ -83,6 +83,7 @@
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DENABLE_WEBRTC=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
@@ -113,6 +114,7 @@
 # Include paths placed before CFLAGS/CPPFLAGS
 LOCAL_C_INCLUDES_Debug := \
 	$(gyp_shared_intermediate_dir)/shim_headers/ashmem/target \
+	$(gyp_shared_intermediate_dir) \
 	$(LOCAL_PATH) \
 	$(PWD)/frameworks/wilhelm/include \
 	$(PWD)/bionic \
@@ -175,6 +177,7 @@
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DENABLE_WEBRTC=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
@@ -206,6 +209,7 @@
 # Include paths placed before CFLAGS/CPPFLAGS
 LOCAL_C_INCLUDES_Release := \
 	$(gyp_shared_intermediate_dir)/shim_headers/ashmem/target \
+	$(gyp_shared_intermediate_dir) \
 	$(LOCAL_PATH) \
 	$(PWD)/frameworks/wilhelm/include \
 	$(PWD)/bionic \
diff --git a/sandbox/seccomp_bpf.target.darwin-x86_64.mk b/sandbox/seccomp_bpf.target.darwin-x86_64.mk
index 69676fc..67372ef 100644
--- a/sandbox/seccomp_bpf.target.darwin-x86_64.mk
+++ b/sandbox/seccomp_bpf.target.darwin-x86_64.mk
@@ -82,6 +82,7 @@
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DENABLE_WEBRTC=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
@@ -112,6 +113,7 @@
 # Include paths placed before CFLAGS/CPPFLAGS
 LOCAL_C_INCLUDES_Debug := \
 	$(gyp_shared_intermediate_dir)/shim_headers/ashmem/target \
+	$(gyp_shared_intermediate_dir) \
 	$(LOCAL_PATH) \
 	$(PWD)/frameworks/wilhelm/include \
 	$(PWD)/bionic \
@@ -173,6 +175,7 @@
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DENABLE_WEBRTC=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
@@ -204,6 +207,7 @@
 # Include paths placed before CFLAGS/CPPFLAGS
 LOCAL_C_INCLUDES_Release := \
 	$(gyp_shared_intermediate_dir)/shim_headers/ashmem/target \
+	$(gyp_shared_intermediate_dir) \
 	$(LOCAL_PATH) \
 	$(PWD)/frameworks/wilhelm/include \
 	$(PWD)/bionic \
diff --git a/sandbox/seccomp_bpf.target.linux-arm.mk b/sandbox/seccomp_bpf.target.linux-arm.mk
index 42ca308..044e15f 100644
--- a/sandbox/seccomp_bpf.target.linux-arm.mk
+++ b/sandbox/seccomp_bpf.target.linux-arm.mk
@@ -88,6 +88,7 @@
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DENABLE_WEBRTC=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
@@ -118,6 +119,7 @@
 # Include paths placed before CFLAGS/CPPFLAGS
 LOCAL_C_INCLUDES_Debug := \
 	$(gyp_shared_intermediate_dir)/shim_headers/ashmem/target \
+	$(gyp_shared_intermediate_dir) \
 	$(LOCAL_PATH) \
 	$(PWD)/frameworks/wilhelm/include \
 	$(PWD)/bionic \
@@ -186,6 +188,7 @@
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DENABLE_WEBRTC=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
@@ -217,6 +220,7 @@
 # Include paths placed before CFLAGS/CPPFLAGS
 LOCAL_C_INCLUDES_Release := \
 	$(gyp_shared_intermediate_dir)/shim_headers/ashmem/target \
+	$(gyp_shared_intermediate_dir) \
 	$(LOCAL_PATH) \
 	$(PWD)/frameworks/wilhelm/include \
 	$(PWD)/bionic \
diff --git a/sandbox/seccomp_bpf.target.linux-x86.mk b/sandbox/seccomp_bpf.target.linux-x86.mk
index f807852..00e9eb4 100644
--- a/sandbox/seccomp_bpf.target.linux-x86.mk
+++ b/sandbox/seccomp_bpf.target.linux-x86.mk
@@ -83,6 +83,7 @@
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DENABLE_WEBRTC=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
@@ -113,6 +114,7 @@
 # Include paths placed before CFLAGS/CPPFLAGS
 LOCAL_C_INCLUDES_Debug := \
 	$(gyp_shared_intermediate_dir)/shim_headers/ashmem/target \
+	$(gyp_shared_intermediate_dir) \
 	$(LOCAL_PATH) \
 	$(PWD)/frameworks/wilhelm/include \
 	$(PWD)/bionic \
@@ -175,6 +177,7 @@
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DENABLE_WEBRTC=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
@@ -206,6 +209,7 @@
 # Include paths placed before CFLAGS/CPPFLAGS
 LOCAL_C_INCLUDES_Release := \
 	$(gyp_shared_intermediate_dir)/shim_headers/ashmem/target \
+	$(gyp_shared_intermediate_dir) \
 	$(LOCAL_PATH) \
 	$(PWD)/frameworks/wilhelm/include \
 	$(PWD)/bionic \
diff --git a/sandbox/seccomp_bpf.target.linux-x86_64.mk b/sandbox/seccomp_bpf.target.linux-x86_64.mk
index 69676fc..67372ef 100644
--- a/sandbox/seccomp_bpf.target.linux-x86_64.mk
+++ b/sandbox/seccomp_bpf.target.linux-x86_64.mk
@@ -82,6 +82,7 @@
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DENABLE_WEBRTC=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
@@ -112,6 +113,7 @@
 # Include paths placed before CFLAGS/CPPFLAGS
 LOCAL_C_INCLUDES_Debug := \
 	$(gyp_shared_intermediate_dir)/shim_headers/ashmem/target \
+	$(gyp_shared_intermediate_dir) \
 	$(LOCAL_PATH) \
 	$(PWD)/frameworks/wilhelm/include \
 	$(PWD)/bionic \
@@ -173,6 +175,7 @@
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DENABLE_WEBRTC=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
@@ -204,6 +207,7 @@
 # Include paths placed before CFLAGS/CPPFLAGS
 LOCAL_C_INCLUDES_Release := \
 	$(gyp_shared_intermediate_dir)/shim_headers/ashmem/target \
+	$(gyp_shared_intermediate_dir) \
 	$(LOCAL_PATH) \
 	$(PWD)/frameworks/wilhelm/include \
 	$(PWD)/bionic \
diff --git a/sandbox/seccomp_bpf_helpers.target.darwin-arm.mk b/sandbox/seccomp_bpf_helpers.target.darwin-arm.mk
index fb443a5..93273e3 100644
--- a/sandbox/seccomp_bpf_helpers.target.darwin-arm.mk
+++ b/sandbox/seccomp_bpf_helpers.target.darwin-arm.mk
@@ -81,6 +81,7 @@
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DENABLE_WEBRTC=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
@@ -111,6 +112,7 @@
 # Include paths placed before CFLAGS/CPPFLAGS
 LOCAL_C_INCLUDES_Debug := \
 	$(gyp_shared_intermediate_dir)/shim_headers/ashmem/target \
+	$(gyp_shared_intermediate_dir) \
 	$(LOCAL_PATH) \
 	$(PWD)/frameworks/wilhelm/include \
 	$(PWD)/bionic \
@@ -179,6 +181,7 @@
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DENABLE_WEBRTC=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
@@ -210,6 +213,7 @@
 # Include paths placed before CFLAGS/CPPFLAGS
 LOCAL_C_INCLUDES_Release := \
 	$(gyp_shared_intermediate_dir)/shim_headers/ashmem/target \
+	$(gyp_shared_intermediate_dir) \
 	$(LOCAL_PATH) \
 	$(PWD)/frameworks/wilhelm/include \
 	$(PWD)/bionic \
diff --git a/sandbox/seccomp_bpf_helpers.target.darwin-x86.mk b/sandbox/seccomp_bpf_helpers.target.darwin-x86.mk
index c6e2225..568602d 100644
--- a/sandbox/seccomp_bpf_helpers.target.darwin-x86.mk
+++ b/sandbox/seccomp_bpf_helpers.target.darwin-x86.mk
@@ -76,6 +76,7 @@
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DENABLE_WEBRTC=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
@@ -106,6 +107,7 @@
 # Include paths placed before CFLAGS/CPPFLAGS
 LOCAL_C_INCLUDES_Debug := \
 	$(gyp_shared_intermediate_dir)/shim_headers/ashmem/target \
+	$(gyp_shared_intermediate_dir) \
 	$(LOCAL_PATH) \
 	$(PWD)/frameworks/wilhelm/include \
 	$(PWD)/bionic \
@@ -168,6 +170,7 @@
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DENABLE_WEBRTC=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
@@ -199,6 +202,7 @@
 # Include paths placed before CFLAGS/CPPFLAGS
 LOCAL_C_INCLUDES_Release := \
 	$(gyp_shared_intermediate_dir)/shim_headers/ashmem/target \
+	$(gyp_shared_intermediate_dir) \
 	$(LOCAL_PATH) \
 	$(PWD)/frameworks/wilhelm/include \
 	$(PWD)/bionic \
diff --git a/sandbox/seccomp_bpf_helpers.target.darwin-x86_64.mk b/sandbox/seccomp_bpf_helpers.target.darwin-x86_64.mk
index d442273..436c507 100644
--- a/sandbox/seccomp_bpf_helpers.target.darwin-x86_64.mk
+++ b/sandbox/seccomp_bpf_helpers.target.darwin-x86_64.mk
@@ -75,6 +75,7 @@
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DENABLE_WEBRTC=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
@@ -105,6 +106,7 @@
 # Include paths placed before CFLAGS/CPPFLAGS
 LOCAL_C_INCLUDES_Debug := \
 	$(gyp_shared_intermediate_dir)/shim_headers/ashmem/target \
+	$(gyp_shared_intermediate_dir) \
 	$(LOCAL_PATH) \
 	$(PWD)/frameworks/wilhelm/include \
 	$(PWD)/bionic \
@@ -166,6 +168,7 @@
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DENABLE_WEBRTC=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
@@ -197,6 +200,7 @@
 # Include paths placed before CFLAGS/CPPFLAGS
 LOCAL_C_INCLUDES_Release := \
 	$(gyp_shared_intermediate_dir)/shim_headers/ashmem/target \
+	$(gyp_shared_intermediate_dir) \
 	$(LOCAL_PATH) \
 	$(PWD)/frameworks/wilhelm/include \
 	$(PWD)/bionic \
diff --git a/sandbox/seccomp_bpf_helpers.target.linux-arm.mk b/sandbox/seccomp_bpf_helpers.target.linux-arm.mk
index fb443a5..93273e3 100644
--- a/sandbox/seccomp_bpf_helpers.target.linux-arm.mk
+++ b/sandbox/seccomp_bpf_helpers.target.linux-arm.mk
@@ -81,6 +81,7 @@
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DENABLE_WEBRTC=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
@@ -111,6 +112,7 @@
 # Include paths placed before CFLAGS/CPPFLAGS
 LOCAL_C_INCLUDES_Debug := \
 	$(gyp_shared_intermediate_dir)/shim_headers/ashmem/target \
+	$(gyp_shared_intermediate_dir) \
 	$(LOCAL_PATH) \
 	$(PWD)/frameworks/wilhelm/include \
 	$(PWD)/bionic \
@@ -179,6 +181,7 @@
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DENABLE_WEBRTC=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
@@ -210,6 +213,7 @@
 # Include paths placed before CFLAGS/CPPFLAGS
 LOCAL_C_INCLUDES_Release := \
 	$(gyp_shared_intermediate_dir)/shim_headers/ashmem/target \
+	$(gyp_shared_intermediate_dir) \
 	$(LOCAL_PATH) \
 	$(PWD)/frameworks/wilhelm/include \
 	$(PWD)/bionic \
diff --git a/sandbox/seccomp_bpf_helpers.target.linux-x86.mk b/sandbox/seccomp_bpf_helpers.target.linux-x86.mk
index c6e2225..568602d 100644
--- a/sandbox/seccomp_bpf_helpers.target.linux-x86.mk
+++ b/sandbox/seccomp_bpf_helpers.target.linux-x86.mk
@@ -76,6 +76,7 @@
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DENABLE_WEBRTC=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
@@ -106,6 +107,7 @@
 # Include paths placed before CFLAGS/CPPFLAGS
 LOCAL_C_INCLUDES_Debug := \
 	$(gyp_shared_intermediate_dir)/shim_headers/ashmem/target \
+	$(gyp_shared_intermediate_dir) \
 	$(LOCAL_PATH) \
 	$(PWD)/frameworks/wilhelm/include \
 	$(PWD)/bionic \
@@ -168,6 +170,7 @@
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DENABLE_WEBRTC=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
@@ -199,6 +202,7 @@
 # Include paths placed before CFLAGS/CPPFLAGS
 LOCAL_C_INCLUDES_Release := \
 	$(gyp_shared_intermediate_dir)/shim_headers/ashmem/target \
+	$(gyp_shared_intermediate_dir) \
 	$(LOCAL_PATH) \
 	$(PWD)/frameworks/wilhelm/include \
 	$(PWD)/bionic \
diff --git a/sandbox/seccomp_bpf_helpers.target.linux-x86_64.mk b/sandbox/seccomp_bpf_helpers.target.linux-x86_64.mk
index d442273..436c507 100644
--- a/sandbox/seccomp_bpf_helpers.target.linux-x86_64.mk
+++ b/sandbox/seccomp_bpf_helpers.target.linux-x86_64.mk
@@ -75,6 +75,7 @@
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DENABLE_WEBRTC=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
@@ -105,6 +106,7 @@
 # Include paths placed before CFLAGS/CPPFLAGS
 LOCAL_C_INCLUDES_Debug := \
 	$(gyp_shared_intermediate_dir)/shim_headers/ashmem/target \
+	$(gyp_shared_intermediate_dir) \
 	$(LOCAL_PATH) \
 	$(PWD)/frameworks/wilhelm/include \
 	$(PWD)/bionic \
@@ -166,6 +168,7 @@
 	'-DUSE_LIBJPEG_TURBO=1' \
 	'-DENABLE_WEBRTC=1' \
 	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_BROWSER_CDMS' \
 	'-DENABLE_CONFIGURATION_POLICY' \
 	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
 	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
@@ -197,6 +200,7 @@
 # Include paths placed before CFLAGS/CPPFLAGS
 LOCAL_C_INCLUDES_Release := \
 	$(gyp_shared_intermediate_dir)/shim_headers/ashmem/target \
+	$(gyp_shared_intermediate_dir) \
 	$(LOCAL_PATH) \
 	$(PWD)/frameworks/wilhelm/include \
 	$(PWD)/bionic \
diff --git a/sandbox/win/sandbox_win.gypi b/sandbox/win/sandbox_win.gypi
index 42644bc..7d9cf94 100644
--- a/sandbox/win/sandbox_win.gypi
+++ b/sandbox/win/sandbox_win.gypi
@@ -74,6 +74,12 @@
             'src/policy_target.h',
             'src/process_mitigations.cc',
             'src/process_mitigations.h',
+            'src/process_mitigations_win32k_dispatcher.cc',
+            'src/process_mitigations_win32k_dispatcher.h',
+            'src/process_mitigations_win32k_interception.cc',
+            'src/process_mitigations_win32k_interception.h',
+            'src/process_mitigations_win32k_policy.cc',
+            'src/process_mitigations_win32k_policy.h',
             'src/process_thread_dispatcher.cc',
             'src/process_thread_dispatcher.h',
             'src/process_thread_interception.cc',
@@ -208,6 +214,7 @@
       'type': 'executable',
       'dependencies': [
         'sandbox',
+        '../base/base.gyp:test_support_base',
         '../testing/gtest.gyp:gtest',
       ],
       'sources': [
@@ -239,6 +246,7 @@
       'type': 'executable',
       'dependencies': [
         'sandbox',
+        '../base/base.gyp:test_support_base',
         '../testing/gtest.gyp:gtest',
       ],
       'sources': [
@@ -255,6 +263,7 @@
       'type': 'executable',
       'dependencies': [
         'sandbox',
+        '../base/base.gyp:test_support_base',
         '../testing/gtest.gyp:gtest',
       ],
       'sources': [
diff --git a/sandbox/win/src/broker_services.cc b/sandbox/win/src/broker_services.cc
index 2350342..895d535 100644
--- a/sandbox/win/src/broker_services.cc
+++ b/sandbox/win/src/broker_services.cc
@@ -278,6 +278,13 @@
           break;
         }
 
+        case JOB_OBJECT_MSG_PROCESS_MEMORY_LIMIT: {
+          BOOL res = ::TerminateJobObject(tracker->job,
+                                          SBOX_FATAL_MEMORY_EXCEEDED);
+          DCHECK(res);
+          break;
+        }
+
         default: {
           NOTREACHED();
           break;
diff --git a/sandbox/win/src/crosscall_server.cc b/sandbox/win/src/crosscall_server.cc
index ab8b421..65a9084 100644
--- a/sandbox/win/src/crosscall_server.cc
+++ b/sandbox/win/src/crosscall_server.cc
@@ -60,7 +60,6 @@
     case 9:
       return reinterpret_cast<ActualCP9*>(buffer_base)->GetSize();
     default:
-      NOTREACHED();
       return 0;
   }
 }
diff --git a/sandbox/win/src/handle_closer.cc b/sandbox/win/src/handle_closer.cc
index d250ec3..30e8977 100644
--- a/sandbox/win/src/handle_closer.cc
+++ b/sandbox/win/src/handle_closer.cc
@@ -154,27 +154,6 @@
   return output <= end;
 }
 
-bool HandleCloser::SetupHandleInterceptions(InterceptionManager* manager) {
-  // We need to intercept CreateThread if we're closing ALPC port clients.
-  HandleMap::iterator names = handles_to_close_.find(L"ALPC Port");
-  if (base::win::GetVersion() >= base::win::VERSION_VISTA &&
-      names != handles_to_close_.end() &&
-      (names->second.empty() || names->second.size() == 0)) {
-    if (!INTERCEPT_EAT(manager, kKerneldllName, CreateThread,
-                       CREATE_THREAD_ID, 28)) {
-      return false;
-    }
-    if (!INTERCEPT_EAT(manager, kKerneldllName, GetUserDefaultLCID,
-                       GET_USER_DEFAULT_LCID_ID, 4)) {
-      return false;
-    }
-
-    return true;
-  }
-
-  return true;
-}
-
 bool GetHandleName(HANDLE handle, base::string16* handle_name) {
   static NtQueryObject QueryObject = NULL;
   if (!QueryObject)
diff --git a/sandbox/win/src/handle_closer.h b/sandbox/win/src/handle_closer.h
index a5808d1..60473b3 100644
--- a/sandbox/win/src/handle_closer.h
+++ b/sandbox/win/src/handle_closer.h
@@ -53,9 +53,6 @@
   // Serializes and copies the closer table into the target process.
   bool InitializeTargetHandles(TargetProcess* target);
 
-  // Adds any interceptions that may be required due to closed system handles.
-  bool SetupHandleInterceptions(InterceptionManager* manager);
-
  private:
   // Calculates the memory needed to copy the serialized handles list (rounded
   // to the nearest machine-word size).
diff --git a/sandbox/win/src/interceptors.h b/sandbox/win/src/interceptors.h
index 43126d0..a17447a 100644
--- a/sandbox/win/src/interceptors.h
+++ b/sandbox/win/src/interceptors.h
@@ -41,9 +41,10 @@
   // Sync dispatcher:
   CREATE_EVENT_ID,
   OPEN_EVENT_ID,
-  // CSRSS bypasses for HandleCloser:
-  CREATE_THREAD_ID,
-  GET_USER_DEFAULT_LCID_ID,
+  // Process mitigations Win32k dispatcher:
+  GDIINITIALIZE_ID,
+  GETSTOCKOBJECT_ID,
+  REGISTERCLASSW_ID,
   INTERCEPTOR_MAX_ID
 };
 
diff --git a/sandbox/win/src/interceptors_64.cc b/sandbox/win/src/interceptors_64.cc
index c71d5a2..ef0b5f0 100644
--- a/sandbox/win/src/interceptors_64.cc
+++ b/sandbox/win/src/interceptors_64.cc
@@ -8,6 +8,7 @@
 #include "sandbox/win/src/filesystem_interception.h"
 #include "sandbox/win/src/named_pipe_interception.h"
 #include "sandbox/win/src/policy_target.h"
+#include "sandbox/win/src/process_mitigations_win32k_interception.h"
 #include "sandbox/win/src/process_thread_interception.h"
 #include "sandbox/win/src/registry_interception.h"
 #include "sandbox/win/src/sandbox_nt_types.h"
@@ -68,23 +69,6 @@
                                    open_as_self, handle_attributes, token);
 }
 
-HANDLE WINAPI TargetCreateThread64(
-    LPSECURITY_ATTRIBUTES thread_attributes, SIZE_T stack_size,
-    LPTHREAD_START_ROUTINE start_address, PVOID parameter, DWORD creation_flags,
-    LPDWORD thread_id) {
-  CreateThreadFunction orig_fn = reinterpret_cast<
-      CreateThreadFunction>(g_originals[CREATE_THREAD_ID]);
-  return TargetCreateThread(orig_fn, thread_attributes, stack_size,
-                            start_address, parameter, creation_flags,
-                            thread_id);
-}
-
-LCID WINAPI TargetGetUserDefaultLCID64(void) {
-  GetUserDefaultLCIDFunction orig_fn = reinterpret_cast<
-      GetUserDefaultLCIDFunction>(g_originals[GET_USER_DEFAULT_LCID_ID]);
-  return TargetGetUserDefaultLCID(orig_fn);
-}
-
 // -----------------------------------------------------------------------
 
 SANDBOX_INTERCEPT NTSTATUS WINAPI TargetNtCreateFile64(
@@ -268,4 +252,27 @@
                            object_attributes);
 }
 
+// -----------------------------------------------------------------------
+
+SANDBOX_INTERCEPT BOOL WINAPI TargetGdiDllInitialize64(
+    HANDLE dll,
+    DWORD reason) {
+  GdiDllInitializeFunction orig_fn = reinterpret_cast<
+      GdiDllInitializeFunction>(g_originals[GDIINITIALIZE_ID]);
+  return TargetGdiDllInitialize(orig_fn, dll, reason);
+}
+
+SANDBOX_INTERCEPT HGDIOBJ WINAPI TargetGetStockObject64(int object) {
+  GetStockObjectFunction orig_fn = reinterpret_cast<
+      GetStockObjectFunction>(g_originals[GETSTOCKOBJECT_ID]);
+  return TargetGetStockObject(orig_fn, object);
+}
+
+SANDBOX_INTERCEPT ATOM WINAPI TargetRegisterClassW64(
+    const WNDCLASS* wnd_class) {
+  RegisterClassWFunction orig_fn = reinterpret_cast<
+      RegisterClassWFunction>(g_originals[REGISTERCLASSW_ID]);
+  return TargetRegisterClassW(orig_fn, wnd_class);
+}
+
 }  // namespace sandbox
diff --git a/sandbox/win/src/interceptors_64.h b/sandbox/win/src/interceptors_64.h
index ef2c10d..7368ceb 100644
--- a/sandbox/win/src/interceptors_64.h
+++ b/sandbox/win/src/interceptors_64.h
@@ -44,15 +44,6 @@
     HANDLE thread, ACCESS_MASK desired_access, BOOLEAN open_as_self,
     ULONG handle_attributes, PHANDLE token);
 
-// Interception of CreateThread on the child process.
-SANDBOX_INTERCEPT HANDLE WINAPI TargetCreateThread64(
-    LPSECURITY_ATTRIBUTES thread_attributes, SIZE_T stack_size,
-    LPTHREAD_START_ROUTINE start_address, PVOID parameter,
-    DWORD creation_flags, LPDWORD thread_id);
-
-// Interception of GetUserDefaultLCID on the child process.
-SANDBOX_INTERCEPT LCID WINAPI TargetGetUserDefaultLCID64();
-
 // -----------------------------------------------------------------------
 // Interceptors handled by the file system dispatcher.
 
@@ -163,6 +154,20 @@
     PHANDLE event_handle, ACCESS_MASK desired_access,
     POBJECT_ATTRIBUTES object_attributes);
 
+// -----------------------------------------------------------------------
+// Interceptors handled by the process mitigations win32k lockdown code.
+
+// Interceptor for the GdiDllInitialize function.
+SANDBOX_INTERCEPT BOOL WINAPI TargetGdiDllInitialize64(
+    HANDLE dll,
+    DWORD reason);
+
+// Interceptor for the GetStockObject function.
+SANDBOX_INTERCEPT HGDIOBJ WINAPI TargetGetStockObject64(int object);
+
+// Interceptor for the RegisterClassW function.
+SANDBOX_INTERCEPT ATOM WINAPI TargetRegisterClassW64(const WNDCLASS* wnd_class);
+
 }  // extern "C"
 
 }  // namespace sandbox
diff --git a/sandbox/win/src/ipc_tags.h b/sandbox/win/src/ipc_tags.h
index 4e3a806..d680411 100644
--- a/sandbox/win/src/ipc_tags.h
+++ b/sandbox/win/src/ipc_tags.h
@@ -29,6 +29,9 @@
   IPC_NTCREATEKEY_TAG,
   IPC_NTOPENKEY_TAG,
   IPC_DUPLICATEHANDLEPROXY_TAG,
+  IPC_GDI_GDIDLLINITIALIZE_TAG,
+  IPC_GDI_GETSTOCKOBJECT_TAG,
+  IPC_USER_REGISTERCLASSW_TAG,
   IPC_LAST_TAG
 };
 
diff --git a/sandbox/win/src/ipc_unittest.cc b/sandbox/win/src/ipc_unittest.cc
index 612ab84..7bdd286 100644
--- a/sandbox/win/src/ipc_unittest.cc
+++ b/sandbox/win/src/ipc_unittest.cc
@@ -315,8 +315,7 @@
   EXPECT_EQ(1, ccp->GetParamsCount());
   delete[] (reinterpret_cast<char*>(ccp));
 
-#if defined(NDEBUG)
-  // Test hat we handle integer overflow on the number of params
+  // Test that we handle integer overflow on the number of params
   // correctly. We use a test-only ctor for ActualCallParams that
   // allows to create malformed cross-call buffers.
   const int32 kPtrDiffSz = sizeof(ptrdiff_t);
@@ -332,7 +331,6 @@
     // If the buffer is malformed the return is NULL.
     EXPECT_TRUE(NULL == ccp);
   }
-#endif  // defined(NDEBUG)
 
   ActualCallParams<1, kBufferSize> params_3(kTag, 1);
   params_3.CopyParamIn(0, &value, sizeof(value), false, ULONG_TYPE);
diff --git a/sandbox/win/src/job.cc b/sandbox/win/src/job.cc
index 62b8d5c..8852ab0 100644
--- a/sandbox/win/src/job.cc
+++ b/sandbox/win/src/job.cc
@@ -16,7 +16,8 @@
 
 DWORD Job::Init(JobLevel security_level,
                 const wchar_t* job_name,
-                DWORD ui_exceptions) {
+                DWORD ui_exceptions,
+                size_t memory_limit) {
   if (job_handle_)
     return ERROR_ALREADY_INITIALIZED;
 
@@ -52,11 +53,11 @@
       jbur.UIRestrictionsClass |= JOB_OBJECT_UILIMIT_EXITWINDOWS;
     }
     case JOB_UNPROTECTED: {
-      // The JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE flag is not supported on
-      // Windows 2000. We need a mechanism on Windows 2000 to ensure
-      // that processes in the job are terminated when the job is closed
-      if (base::win::GetVersion() == base::win::VERSION_PRE_XP)
-        break;
+      if (memory_limit) {
+        jeli.BasicLimitInformation.LimitFlags |=
+            JOB_OBJECT_LIMIT_PROCESS_MEMORY;
+        jeli.ProcessMemoryLimit = memory_limit;
+      }
 
       jeli.BasicLimitInformation.LimitFlags |=
           JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
diff --git a/sandbox/win/src/job.h b/sandbox/win/src/job.h
index 7c215ef..60dc314 100644
--- a/sandbox/win/src/job.h
+++ b/sandbox/win/src/job.h
@@ -31,7 +31,8 @@
   // the error.
   DWORD Init(JobLevel security_level,
              const wchar_t* job_name,
-             DWORD ui_exceptions);
+             DWORD ui_exceptions,
+             size_t memory_limit);
 
   // Assigns the process referenced by process_handle to the job.
   // If the function succeeds, the return value is ERROR_SUCCESS. If the
diff --git a/sandbox/win/src/job_unittest.cc b/sandbox/win/src/job_unittest.cc
index 3b2b331..a1b7aca 100644
--- a/sandbox/win/src/job_unittest.cc
+++ b/sandbox/win/src/job_unittest.cc
@@ -16,7 +16,7 @@
   {
     // Create the job.
     Job job;
-    ASSERT_EQ(ERROR_SUCCESS, job.Init(JOB_LOCKDOWN, L"my_test_job_name", 0));
+    ASSERT_EQ(ERROR_SUCCESS, job.Init(JOB_LOCKDOWN, L"my_test_job_name", 0, 0));
 
     // check if the job exists.
     HANDLE job_handle = ::OpenJobObjectW(GENERIC_ALL, FALSE,
@@ -40,7 +40,7 @@
   {
     // Create the job.
     Job job;
-    ASSERT_EQ(ERROR_SUCCESS, job.Init(JOB_LOCKDOWN, L"my_test_job_name", 0));
+    ASSERT_EQ(ERROR_SUCCESS, job.Init(JOB_LOCKDOWN, L"my_test_job_name", 0, 0));
 
     job_handle = job.Detach();
     ASSERT_TRUE(job_handle != NULL);
@@ -73,7 +73,7 @@
     // Create the job.
     Job job;
     ASSERT_EQ(ERROR_SUCCESS, job.Init(JOB_LOCKDOWN, L"my_test_job_name",
-                                      JOB_OBJECT_UILIMIT_READCLIPBOARD));
+                                      JOB_OBJECT_UILIMIT_READCLIPBOARD, 0));
 
     job_handle = job.Detach();
     ASSERT_TRUE(job_handle != NULL);
@@ -93,7 +93,7 @@
   {
     // Create the job.
     Job job;
-    ASSERT_EQ(ERROR_SUCCESS, job.Init(JOB_LOCKDOWN, L"my_test_job_name", 0));
+    ASSERT_EQ(ERROR_SUCCESS, job.Init(JOB_LOCKDOWN, L"my_test_job_name", 0, 0));
 
     job_handle = job.Detach();
     ASSERT_TRUE(job_handle != NULL);
@@ -115,8 +115,8 @@
 TEST(JobTest, DoubleInit) {
   // Create the job.
   Job job;
-  ASSERT_EQ(ERROR_SUCCESS, job.Init(JOB_LOCKDOWN, L"my_test_job_name", 0));
-  ASSERT_EQ(ERROR_ALREADY_INITIALIZED, job.Init(JOB_LOCKDOWN, L"test", 0));
+  ASSERT_EQ(ERROR_SUCCESS, job.Init(JOB_LOCKDOWN, L"my_test_job_name", 0, 0));
+  ASSERT_EQ(ERROR_ALREADY_INITIALIZED, job.Init(JOB_LOCKDOWN, L"test", 0, 0));
 }
 
 // Tests the error case when we use a method and the object is not yet
@@ -131,34 +131,35 @@
 // Tests the initialization of the job with different security level.
 TEST(JobTest, SecurityLevel) {
   Job job1;
-  ASSERT_EQ(ERROR_SUCCESS, job1.Init(JOB_LOCKDOWN, L"job1", 0));
+  ASSERT_EQ(ERROR_SUCCESS, job1.Init(JOB_LOCKDOWN, L"job1", 0, 0));
 
   Job job2;
-  ASSERT_EQ(ERROR_SUCCESS, job2.Init(JOB_RESTRICTED, L"job2", 0));
+  ASSERT_EQ(ERROR_SUCCESS, job2.Init(JOB_RESTRICTED, L"job2", 0, 0));
 
   Job job3;
-  ASSERT_EQ(ERROR_SUCCESS, job3.Init(JOB_LIMITED_USER, L"job3", 0));
+  ASSERT_EQ(ERROR_SUCCESS, job3.Init(JOB_LIMITED_USER, L"job3", 0, 0));
 
   Job job4;
-  ASSERT_EQ(ERROR_SUCCESS, job4.Init(JOB_INTERACTIVE, L"job4", 0));
+  ASSERT_EQ(ERROR_SUCCESS, job4.Init(JOB_INTERACTIVE, L"job4", 0, 0));
 
   Job job5;
-  ASSERT_EQ(ERROR_SUCCESS, job5.Init(JOB_UNPROTECTED, L"job5", 0));
+  ASSERT_EQ(ERROR_SUCCESS, job5.Init(JOB_UNPROTECTED, L"job5", 0, 0));
 
   // JOB_NONE means we run without a job object so Init should fail.
   Job job6;
-  ASSERT_EQ(ERROR_BAD_ARGUMENTS, job6.Init(JOB_NONE, L"job6", 0));
+  ASSERT_EQ(ERROR_BAD_ARGUMENTS, job6.Init(JOB_NONE, L"job6", 0, 0));
 
   Job job7;
   ASSERT_EQ(ERROR_BAD_ARGUMENTS, job7.Init(
-      static_cast<JobLevel>(JOB_NONE+1), L"job7", 0));
+      static_cast<JobLevel>(JOB_NONE+1), L"job7", 0, 0));
 }
 
 // Tests the method "AssignProcessToJob".
 TEST(JobTest, ProcessInJob) {
   // Create the job.
   Job job;
-  ASSERT_EQ(ERROR_SUCCESS, job.Init(JOB_UNPROTECTED, L"job_test_process", 0));
+  ASSERT_EQ(ERROR_SUCCESS, job.Init(JOB_UNPROTECTED, L"job_test_process", 0,
+                                    0));
 
   BOOL result = FALSE;
 
diff --git a/sandbox/win/src/process_mitigations_test.cc b/sandbox/win/src/process_mitigations_test.cc
index 19e55ba..e606256 100644
--- a/sandbox/win/src/process_mitigations_test.cc
+++ b/sandbox/win/src/process_mitigations_test.cc
@@ -88,7 +88,6 @@
       reinterpret_cast<GetProcessMitigationPolicyFunction>(
           ::GetProcAddress(::GetModuleHandleW(L"kernel32.dll"),
                            "GetProcessMitigationPolicy"));
-
   if (!get_process_mitigation_policy)
     return SBOX_TEST_NOT_FOUND;
 
@@ -103,9 +102,6 @@
   if (!CheckWin8StrictHandlePolicy())
     return SBOX_TEST_THIRD_ERROR;
 
-  if (!CheckWin8Win32CallPolicy())
-    return SBOX_TEST_FOURTH_ERROR;
-
   if (!CheckWin8DllExtensionPolicy())
     return SBOX_TEST_FIFTH_ERROR;
 
@@ -201,5 +197,52 @@
 }
 #endif
 
+SBOX_TESTS_COMMAND int CheckWin8Lockdown(int argc, wchar_t **argv) {
+  get_process_mitigation_policy =
+      reinterpret_cast<GetProcessMitigationPolicyFunction>(
+          ::GetProcAddress(::GetModuleHandleW(L"kernel32.dll"),
+                           "GetProcessMitigationPolicy"));
+  if (!get_process_mitigation_policy)
+    return SBOX_TEST_NOT_FOUND;
+
+  if (!CheckWin8Win32CallPolicy())
+    return SBOX_TEST_FIRST_ERROR;
+  return SBOX_TEST_SUCCEEDED;
+}
+
+// This test validates that setting the MITIGATION_WIN32K_DISABLE mitigation on
+// the target process causes the launch to fail in process initialization.
+// The test process itself links against user32/gdi32.
+TEST(ProcessMitigationsTest, CheckWin8Win32KLockDownFailure) {
+  if (base::win::GetVersion() < base::win::VERSION_WIN8)
+    return;
+
+  TestRunner runner;
+  sandbox::TargetPolicy* policy = runner.GetPolicy();
+
+  EXPECT_EQ(policy->SetProcessMitigations(MITIGATION_WIN32K_DISABLE),
+            SBOX_ALL_OK);
+  EXPECT_NE(SBOX_TEST_SUCCEEDED, runner.RunTest(L"CheckWin8Lockdown"));
+}
+
+// This test validates that setting the MITIGATION_WIN32K_DISABLE mitigation
+// along with the policy to fake user32 and gdi32 initialization successfully
+// launches the target process.
+// The test process itself links against user32/gdi32.
+TEST(ProcessMitigationsTest, CheckWin8Win32KLockDownSuccess) {
+  if (base::win::GetVersion() < base::win::VERSION_WIN8)
+    return;
+
+  TestRunner runner;
+  sandbox::TargetPolicy* policy = runner.GetPolicy();
+
+  EXPECT_EQ(policy->SetProcessMitigations(MITIGATION_WIN32K_DISABLE),
+            SBOX_ALL_OK);
+  EXPECT_EQ(policy->AddRule(sandbox::TargetPolicy::SUBSYS_WIN32K_LOCKDOWN,
+                            sandbox::TargetPolicy::FAKE_USER_GDI_INIT, NULL),
+            sandbox::SBOX_ALL_OK);
+  EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"CheckWin8Lockdown"));
+}
+
 }  // namespace sandbox
 
diff --git a/sandbox/win/src/process_mitigations_win32k_dispatcher.cc b/sandbox/win/src/process_mitigations_win32k_dispatcher.cc
new file mode 100644
index 0000000..e426084
--- /dev/null
+++ b/sandbox/win/src/process_mitigations_win32k_dispatcher.cc
@@ -0,0 +1,57 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/win/src/process_mitigations_win32k_dispatcher.h"
+#include "sandbox/win/src/interception.h"
+#include "sandbox/win/src/interceptors.h"
+#include "sandbox/win/src/ipc_tags.h"
+#include "sandbox/win/src/process_mitigations_win32k_interception.h"
+
+namespace sandbox {
+
+ProcessMitigationsWin32KDispatcher::ProcessMitigationsWin32KDispatcher(
+    PolicyBase* policy_base)
+    : policy_base_(policy_base) {
+}
+
+bool ProcessMitigationsWin32KDispatcher::SetupService(
+    InterceptionManager* manager, int service) {
+  if (!(policy_base_->GetProcessMitigations() &
+        sandbox::MITIGATION_WIN32K_DISABLE)) {
+    return false;
+  }
+
+  switch (service) {
+    case IPC_GDI_GDIDLLINITIALIZE_TAG: {
+      if (!INTERCEPT_EAT(manager, L"gdi32.dll", GdiDllInitialize,
+                         GDIINITIALIZE_ID, 12)) {
+        return false;
+      }
+      return true;
+    }
+
+    case IPC_GDI_GETSTOCKOBJECT_TAG: {
+      if (!INTERCEPT_EAT(manager, L"gdi32.dll", GetStockObject,
+                         GETSTOCKOBJECT_ID, 8)) {
+        return false;
+      }
+      return true;
+    }
+
+    case IPC_USER_REGISTERCLASSW_TAG: {
+      if (!INTERCEPT_EAT(manager, L"user32.dll", RegisterClassW,
+                         REGISTERCLASSW_ID, 8)) {
+        return false;
+      }
+      return true;
+    }
+
+    default:
+      break;
+  }
+  return false;
+}
+
+}  // namespace sandbox
+
diff --git a/sandbox/win/src/process_mitigations_win32k_dispatcher.h b/sandbox/win/src/process_mitigations_win32k_dispatcher.h
new file mode 100644
index 0000000..65c9f77
--- /dev/null
+++ b/sandbox/win/src/process_mitigations_win32k_dispatcher.h
@@ -0,0 +1,31 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_SRC_PROCESS_MITIGATIONS_WIN32K_DISPATCHER_H_
+#define SANDBOX_SRC_PROCESS_MITIGATIONS_WIN32K_DISPATCHER_H_
+
+#include "base/basictypes.h"
+#include "sandbox/win/src/sandbox_policy_base.h"
+
+namespace sandbox {
+
+// This class sets up intercepts for the Win32K lockdown policy which is set
+// on Windows 8 and beyond.
+class ProcessMitigationsWin32KDispatcher : public Dispatcher {
+ public:
+  explicit ProcessMitigationsWin32KDispatcher(PolicyBase* policy_base);
+  ~ProcessMitigationsWin32KDispatcher() {}
+
+  // Dispatcher interface.
+  virtual bool SetupService(InterceptionManager* manager, int service);
+
+ private:
+  PolicyBase* policy_base_;
+
+  DISALLOW_COPY_AND_ASSIGN(ProcessMitigationsWin32KDispatcher);
+};
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_SRC_PROCESS_MITIGATIONS_WIN32K_DISPATCHER_H_
diff --git a/sandbox/win/src/process_mitigations_win32k_interception.cc b/sandbox/win/src/process_mitigations_win32k_interception.cc
new file mode 100644
index 0000000..ee24fbf
--- /dev/null
+++ b/sandbox/win/src/process_mitigations_win32k_interception.cc
@@ -0,0 +1,29 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/win/src/process_mitigations_win32k_interception.h"
+
+namespace sandbox {
+
+BOOL WINAPI TargetGdiDllInitialize(
+    GdiDllInitializeFunction orig_gdi_dll_initialize,
+    HANDLE dll,
+    DWORD reason) {
+  return TRUE;
+}
+
+HGDIOBJ WINAPI TargetGetStockObject(
+    GetStockObjectFunction orig_get_stock_object,
+    int object) {
+  return reinterpret_cast<HGDIOBJ>(NULL);
+}
+
+ATOM WINAPI TargetRegisterClassW(
+    RegisterClassWFunction orig_register_class_function,
+    const WNDCLASS* wnd_class) {
+  return TRUE;
+}
+
+}  // namespace sandbox
+
diff --git a/sandbox/win/src/process_mitigations_win32k_interception.h b/sandbox/win/src/process_mitigations_win32k_interception.h
new file mode 100644
index 0000000..bf7b551
--- /dev/null
+++ b/sandbox/win/src/process_mitigations_win32k_interception.h
@@ -0,0 +1,46 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_SRC_PROCESS_MITIGATIONS_WIN32K_INTERCEPTION_H_
+#define SANDBOX_SRC_PROCESS_MITIGATIONS_WIN32K_INTERCEPTION_H_
+
+#include <windows.h>
+#include "base/basictypes.h"
+#include "sandbox/win/src/sandbox_types.h"
+
+namespace sandbox {
+
+extern "C" {
+
+typedef BOOL (WINAPI* GdiDllInitializeFunction) (
+    HANDLE dll,
+    DWORD reason,
+    LPVOID reserved);
+
+typedef HGDIOBJ (WINAPI *GetStockObjectFunction) (int object);
+
+typedef ATOM (WINAPI *RegisterClassWFunction) (const WNDCLASS* wnd_class);
+
+// Interceptor for the  GdiDllInitialize function.
+SANDBOX_INTERCEPT BOOL WINAPI TargetGdiDllInitialize(
+    GdiDllInitializeFunction orig_gdi_dll_initialize,
+    HANDLE dll,
+    DWORD reason);
+
+// Interceptor for the GetStockObject function.
+SANDBOX_INTERCEPT HGDIOBJ WINAPI TargetGetStockObject(
+    GetStockObjectFunction orig_get_stock_object,
+    int object);
+
+// Interceptor for the RegisterClassW function.
+SANDBOX_INTERCEPT ATOM WINAPI TargetRegisterClassW(
+    RegisterClassWFunction orig_register_class_function,
+    const WNDCLASS* wnd_class);
+
+}  // extern "C"
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_SRC_PROCESS_MITIGATIONS_WIN32K_INTERCEPTION_H_
+
diff --git a/sandbox/win/src/process_mitigations_win32k_policy.cc b/sandbox/win/src/process_mitigations_win32k_policy.cc
new file mode 100644
index 0000000..af18c54
--- /dev/null
+++ b/sandbox/win/src/process_mitigations_win32k_policy.cc
@@ -0,0 +1,24 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/win/src/process_mitigations_win32k_policy.h"
+
+namespace sandbox {
+
+bool ProcessMitigationsWin32KLockdownPolicy::GenerateRules(
+    const wchar_t* name,
+    TargetPolicy::Semantics semantics,
+    LowLevelPolicy* policy) {
+  PolicyRule rule(FAKE_SUCCESS);
+  if (!policy->AddRule(IPC_GDI_GDIDLLINITIALIZE_TAG, &rule))
+    return false;
+  if (!policy->AddRule(IPC_GDI_GETSTOCKOBJECT_TAG, &rule))
+    return false;
+  if (!policy->AddRule(IPC_USER_REGISTERCLASSW_TAG, &rule))
+    return false;
+  return true;
+}
+
+}  // namespace sandbox
+
diff --git a/sandbox/win/src/process_mitigations_win32k_policy.h b/sandbox/win/src/process_mitigations_win32k_policy.h
new file mode 100644
index 0000000..078ed2b
--- /dev/null
+++ b/sandbox/win/src/process_mitigations_win32k_policy.h
@@ -0,0 +1,35 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_SRC_PROCESS_MITIGATIONS_WIN32K_POLICY_H_
+#define SANDBOX_SRC_PROCESS_MITIGATIONS_WIN32K_POLICY_H_
+
+#include "base/basictypes.h"
+#include "sandbox/win/src/crosscall_server.h"
+#include "sandbox/win/src/policy_low_level.h"
+#include "sandbox/win/src/sandbox_policy.h"
+
+namespace sandbox {
+
+enum EvalResult;
+
+// This class centralizes most of the knowledge related to the process
+// mitigations Win32K lockdown policy.
+class ProcessMitigationsWin32KLockdownPolicy {
+ public:
+  // Creates the required low-level policy rules to evaluate a high-level
+  // policy rule for the Win32K process mitigation policy.
+  // name is the object name, semantics is the desired semantics for the
+  // open or create and policy is the policy generator to which the rules are
+  // going to be added.
+  static bool GenerateRules(const wchar_t* name,
+                            TargetPolicy::Semantics semantics,
+                            LowLevelPolicy* policy);
+};
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_SRC_PROCESS_MITIGATIONS_WIN32K_POLICY_H_
+
+
diff --git a/sandbox/win/src/process_thread_interception.cc b/sandbox/win/src/process_thread_interception.cc
index d351ee5..45926bc 100644
--- a/sandbox/win/src/process_thread_interception.cc
+++ b/sandbox/win/src/process_thread_interception.cc
@@ -400,50 +400,4 @@
   return FALSE;
 }
 
-// Creates a thread without registering with CSRSS. This is required if we
-// closed the CSRSS ALPC port after lockdown.
-HANDLE WINAPI TargetCreateThread(CreateThreadFunction orig_CreateThread,
-                                 LPSECURITY_ATTRIBUTES thread_attributes,
-                                 SIZE_T stack_size,
-                                 LPTHREAD_START_ROUTINE start_address,
-                                 PVOID parameter,
-                                 DWORD creation_flags,
-                                 LPDWORD thread_id) {
-// Try the normal CreateThread; switch to RtlCreateUserThread if needed.
-  static bool use_create_thread = true;
-  HANDLE thread;
-  if (use_create_thread) {
-    thread = orig_CreateThread(thread_attributes, stack_size, start_address,
-                               parameter, creation_flags, thread_id);
-    if (thread)
-      return thread;
-  }
-
-  PSECURITY_DESCRIPTOR sd =
-      thread_attributes ? thread_attributes->lpSecurityDescriptor : NULL;
-  CLIENT_ID client_id;
-
-  NTSTATUS result = g_nt.RtlCreateUserThread(NtCurrentProcess, sd,
-                                             creation_flags & CREATE_SUSPENDED,
-                                             0, stack_size, 0, start_address,
-                                             parameter, &thread, &client_id);
-  if (!NT_SUCCESS(result))
-    return 0;
-
-  // CSRSS is closed if we got here, so use RtlCreateUserThread from here on.
-  use_create_thread = false;
-  if (thread_id)
-    *thread_id = HandleToUlong(client_id.UniqueThread);
-  return thread;
-}
-
-// Cache the default LCID to avoid pinging CSRSS after lockdown.
-// TODO(jschuh): This approach will miss a default locale changes after
-// lockdown. In the future we may want to have the broker check instead.
-LCID WINAPI TargetGetUserDefaultLCID(
-    GetUserDefaultLCIDFunction orig_GetUserDefaultLCID) {
-  static LCID default_lcid = orig_GetUserDefaultLCID();
-  return default_lcid;
-}
-
 }  // namespace sandbox
diff --git a/sandbox/win/src/process_thread_interception.h b/sandbox/win/src/process_thread_interception.h
index 7d2d533..31dc231 100644
--- a/sandbox/win/src/process_thread_interception.h
+++ b/sandbox/win/src/process_thread_interception.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2006-2011 The Chromium Authors. All rights reserved.
+// Copyright (c) 2014 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
@@ -83,17 +83,6 @@
     LPVOID environment, LPCSTR current_directory, LPSTARTUPINFOA startup_info,
     LPPROCESS_INFORMATION process_information);
 
-// Interception of CreateThread in kernel32.dll.
-SANDBOX_INTERCEPT HANDLE WINAPI TargetCreateThread(
-    CreateThreadFunction orig_CreateThread,
-    LPSECURITY_ATTRIBUTES thread_attributes, SIZE_T stack_size,
-    LPTHREAD_START_ROUTINE start_address, PVOID parameter,
-    DWORD creation_flags, LPDWORD thread_id);
-
-// Interception of GetUserDefaultLCID in kernel32.dll.
-SANDBOX_INTERCEPT LCID WINAPI TargetGetUserDefaultLCID(
-    GetUserDefaultLCIDFunction orig_GetUserDefaultLCID);
-
 }  // extern "C"
 
 }  // namespace sandbox
diff --git a/sandbox/win/src/restricted_token.cc b/sandbox/win/src/restricted_token.cc
index 64973e9..3960926 100644
--- a/sandbox/win/src/restricted_token.cc
+++ b/sandbox/win/src/restricted_token.cc
@@ -14,7 +14,6 @@
 namespace sandbox {
 
 unsigned RestrictedToken::Init(const HANDLE effective_token) {
-  DCHECK(!init_);
   if (init_)
     return ERROR_ALREADY_INITIALIZED;
 
diff --git a/sandbox/win/src/restricted_token_unittest.cc b/sandbox/win/src/restricted_token_unittest.cc
index 480106e..8186f9c 100644
--- a/sandbox/win/src/restricted_token_unittest.cc
+++ b/sandbox/win/src/restricted_token_unittest.cc
@@ -408,8 +408,8 @@
 // elements in the restricting sids list has to be equal.
 void CheckRestrictingSid(const ATL::CAccessToken &restricted_token,
                          ATL::CSid sid, int count) {
-  DWORD length = 1000;
-  BYTE *memory = new BYTE[1000];
+  DWORD length = 8192;
+  BYTE *memory = new BYTE[length];
   TOKEN_GROUPS *groups = reinterpret_cast<TOKEN_GROUPS*>(memory);
   ASSERT_TRUE(::GetTokenInformation(restricted_token.GetHandle(),
                                     TokenRestrictedSids,
@@ -530,8 +530,8 @@
   ATL::CSid session;
   restricted_token.GetLogonSid(&session);
 
-  DWORD length = 1000;
-  BYTE *memory = new BYTE[1000];
+  DWORD length = 8192;
+  BYTE *memory = new BYTE[length];
   TOKEN_GROUPS *groups = reinterpret_cast<TOKEN_GROUPS*>(memory);
   ASSERT_TRUE(::GetTokenInformation(restricted_token.GetHandle(),
                                     TokenRestrictedSids,
@@ -577,9 +577,6 @@
   CheckRestrictingSid(restricted_token, user, -1);
 }
 
-// Test to be executed only in release because they are triggering DCHECKs.
-#ifndef _DEBUG
-
 // Checks the error code when the object is initialized twice.
 TEST(RestrictedTokenTest, DoubleInit) {
   RestrictedToken token;
@@ -588,6 +585,4 @@
   ASSERT_EQ(ERROR_ALREADY_INITIALIZED, token.Init(NULL));
 }
 
-#endif
-
 }  // namespace sandbox
diff --git a/sandbox/win/src/restricted_token_utils.cc b/sandbox/win/src/restricted_token_utils.cc
index f3b1859..93b212e 100644
--- a/sandbox/win/src/restricted_token_utils.cc
+++ b/sandbox/win/src/restricted_token_utils.cc
@@ -146,7 +146,7 @@
                                   JobLevel job_level,
                                   HANDLE *const job_handle_ret) {
   Job job;
-  DWORD err_code = job.Init(job_level, NULL, 0);
+  DWORD err_code = job.Init(job_level, NULL, 0, 0);
   if (ERROR_SUCCESS != err_code)
     return err_code;
 
diff --git a/sandbox/win/src/sandbox_policy.h b/sandbox/win/src/sandbox_policy.h
index 4694fbe..22a2049 100644
--- a/sandbox/win/src/sandbox_policy.h
+++ b/sandbox/win/src/sandbox_policy.h
@@ -26,7 +26,8 @@
     SUBSYS_PROCESS,           // Creation of child processes.
     SUBSYS_REGISTRY,          // Creation and opening of registry keys.
     SUBSYS_SYNC,              // Creation of named sync objects.
-    SUBSYS_HANDLES            // Duplication of handles to other processes.
+    SUBSYS_HANDLES,           // Duplication of handles to other processes.
+    SUBSYS_WIN32K_LOCKDOWN    // Win32K Lockdown related policy.
   };
 
   // Allowable semantics when a rule is matched.
@@ -52,7 +53,10 @@
     EVENTS_ALLOW_ANY,      // Allows the creation of an event with full access.
     EVENTS_ALLOW_READONLY, // Allows opening an even with synchronize access.
     REG_ALLOW_READONLY,    // Allows readonly access to a registry key.
-    REG_ALLOW_ANY          // Allows read and write access to a registry key.
+    REG_ALLOW_ANY,         // Allows read and write access to a registry key.
+    FAKE_USER_GDI_INIT     // Fakes user32 and gdi32 initialization. This can
+                           // be used to allow the DLLs to load and initialize
+                           // even if the process cannot access that subsystem.
   };
 
   // Increments the reference count of this object. The reference count must
@@ -128,6 +132,11 @@
   // Note: the recommended level is JOB_RESTRICTED or JOB_LOCKDOWN.
   virtual ResultCode SetJobLevel(JobLevel job_level, uint32 ui_exceptions) = 0;
 
+  // Sets a hard limit on the size of the commit set for the sandboxed process.
+  // If the limit is reached, the process will be terminated with
+  // SBOX_FATAL_MEMORY_EXCEEDED (7012).
+  virtual ResultCode SetJobMemoryLimit(size_t memory_limit) = 0;
+
   // Specifies the desktop on which the application is going to run. If the
   // desktop does not exist, it will be created. If alternate_winstation is
   // set to true, the desktop will be created on an alternate window station.
diff --git a/sandbox/win/src/sandbox_policy_base.cc b/sandbox/win/src/sandbox_policy_base.cc
index 3077604..711fafc 100644
--- a/sandbox/win/src/sandbox_policy_base.cc
+++ b/sandbox/win/src/sandbox_policy_base.cc
@@ -21,6 +21,8 @@
 #include "sandbox/win/src/policy_broker.h"
 #include "sandbox/win/src/policy_engine_processor.h"
 #include "sandbox/win/src/policy_low_level.h"
+#include "sandbox/win/src/process_mitigations_win32k_dispatcher.h"
+#include "sandbox/win/src/process_mitigations_win32k_policy.h"
 #include "sandbox/win/src/process_thread_dispatcher.h"
 #include "sandbox/win/src/process_thread_policy.h"
 #include "sandbox/win/src/registry_dispatcher.h"
@@ -80,6 +82,7 @@
       initial_level_(USER_LOCKDOWN),
       job_level_(JOB_LOCKDOWN),
       ui_exceptions_(0),
+      memory_limit_(0),
       use_alternate_desktop_(false),
       use_alternate_winstation_(false),
       file_system_init_(false),
@@ -124,6 +127,11 @@
 
   dispatcher = new HandleDispatcher(this);
   ipc_targets_[IPC_DUPLICATEHANDLEPROXY_TAG] = dispatcher;
+
+  dispatcher = new ProcessMitigationsWin32KDispatcher(this);
+  ipc_targets_[IPC_GDI_GDIDLLINITIALIZE_TAG] = dispatcher;
+  ipc_targets_[IPC_GDI_GETSTOCKOBJECT_TAG] = dispatcher;
+  ipc_targets_[IPC_USER_REGISTERCLASSW_TAG] = dispatcher;
 }
 
 PolicyBase::~PolicyBase() {
@@ -170,11 +178,22 @@
 }
 
 ResultCode PolicyBase::SetJobLevel(JobLevel job_level, uint32 ui_exceptions) {
+  if (memory_limit_ && job_level == JOB_NONE) {
+    return SBOX_ERROR_BAD_PARAMS;
+  }
   job_level_ = job_level;
   ui_exceptions_ = ui_exceptions;
   return SBOX_ALL_OK;
 }
 
+ResultCode PolicyBase::SetJobMemoryLimit(size_t memory_limit) {
+  if (memory_limit && job_level_ == JOB_NONE) {
+    return SBOX_ERROR_BAD_PARAMS;
+  }
+  memory_limit_ = memory_limit;
+  return SBOX_ALL_OK;
+}
+
 ResultCode PolicyBase::SetAlternateDesktop(bool alternate_winstation) {
   use_alternate_desktop_ = true;
   use_alternate_winstation_ = alternate_winstation;
@@ -413,6 +432,16 @@
       }
       break;
     }
+
+    case SUBSYS_WIN32K_LOCKDOWN: {
+      if (!ProcessMitigationsWin32KLockdownPolicy::GenerateRules(
+              pattern, semantics,policy_maker_)) {
+        NOTREACHED();
+        return SBOX_ERROR_BAD_PARAMS;
+      }
+      break;
+    }
+
     default: {
       return SBOX_ERROR_UNSUPPORTED;
     }
@@ -471,7 +500,8 @@
   if (job_level_ != JOB_NONE) {
     // Create the windows job object.
     Job job_obj;
-    DWORD result = job_obj.Init(job_level_, NULL, ui_exceptions_);
+    DWORD result = job_obj.Init(job_level_, NULL, ui_exceptions_,
+                                memory_limit_);
     if (ERROR_SUCCESS != result) {
       return SBOX_ERROR_GENERIC;
     }
@@ -667,9 +697,6 @@
     }
   }
 
-  if (!handle_closer_.SetupHandleInterceptions(&manager))
-    return false;
-
   if (!SetupBasicInterceptions(&manager))
     return false;
 
diff --git a/sandbox/win/src/sandbox_policy_base.h b/sandbox/win/src/sandbox_policy_base.h
index 179cb6c..540f261 100644
--- a/sandbox/win/src/sandbox_policy_base.h
+++ b/sandbox/win/src/sandbox_policy_base.h
@@ -45,6 +45,7 @@
   virtual TokenLevel GetLockdownTokenLevel() const OVERRIDE;
   virtual ResultCode SetJobLevel(JobLevel job_level,
                                  uint32 ui_exceptions) OVERRIDE;
+  virtual ResultCode SetJobMemoryLimit(size_t memory_limit) OVERRIDE;
   virtual ResultCode SetAlternateDesktop(bool alternate_winstation) OVERRIDE;
   virtual base::string16 GetAlternateDesktop() const OVERRIDE;
   virtual ResultCode CreateAlternateDesktop(bool alternate_winstation) OVERRIDE;
@@ -127,6 +128,7 @@
   TokenLevel initial_level_;
   JobLevel job_level_;
   uint32 ui_exceptions_;
+  size_t memory_limit_;
   bool use_alternate_desktop_;
   bool use_alternate_winstation_;
   // Helps the file system policy initialization.
diff --git a/sandbox/win/src/sandbox_types.h b/sandbox/win/src/sandbox_types.h
index 48f1b61..22840ce 100644
--- a/sandbox/win/src/sandbox_types.h
+++ b/sandbox/win/src/sandbox_types.h
@@ -58,6 +58,7 @@
   SBOX_FATAL_CACHEDISABLE = 7009,    // Failed to forbid HCKU caching.
   SBOX_FATAL_CLOSEHANDLES = 7010,    // Failed to close pending handles.
   SBOX_FATAL_MITIGATION = 7011,      // Could not set the mitigation policy.
+  SBOX_FATAL_MEMORY_EXCEEDED = 7012, // Exceeded the job memory limit.
   SBOX_FATAL_LAST
 };
 
diff --git a/sandbox/win/tests/integration_tests/integration_tests.cc b/sandbox/win/tests/integration_tests/integration_tests.cc
index 1996430..bb80931 100644
--- a/sandbox/win/tests/integration_tests/integration_tests.cc
+++ b/sandbox/win/tests/integration_tests/integration_tests.cc
@@ -2,6 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "base/bind.h"
+#include "base/test/launcher/unit_test_launcher.h"
+#include "base/test/test_suite.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "sandbox/win/tests/common/controller.h"
 
@@ -13,6 +16,10 @@
       return sandbox::DispatchCall(argc, argv);
   }
 
-  testing::InitGoogleTest(&argc, argv);
-  return RUN_ALL_TESTS();
+  TestSuite test_suite(argc, argv);
+  return base::LaunchUnitTests(
+      argc,
+      argv,
+      false,
+      base::Bind(&base::TestSuite::Run, base::Unretained(&test_suite)));
 }
diff --git a/sandbox/win/tests/unit_tests/unit_tests.cc b/sandbox/win/tests/unit_tests/unit_tests.cc
index a9623db..df98ba2 100644
--- a/sandbox/win/tests/unit_tests/unit_tests.cc
+++ b/sandbox/win/tests/unit_tests/unit_tests.cc
@@ -2,6 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "base/bind.h"
+#include "base/test/launcher/unit_test_launcher.h"
+#include "base/test/test_suite.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 int wmain(int argc, wchar_t **argv) {
@@ -11,6 +14,10 @@
       return 0;
   }
 
-  testing::InitGoogleTest(&argc, argv);
-  return RUN_ALL_TESTS();
+  TestSuite test_suite(argc, argv);
+  return base::LaunchUnitTests(
+      argc,
+      argv,
+      false,
+      base::Bind(&base::TestSuite::Run, base::Unretained(&test_suite)));
 }
diff --git a/sandbox/win/tests/validation_tests/commands.cc b/sandbox/win/tests/validation_tests/commands.cc
index e7620c3..4b12094 100644
--- a/sandbox/win/tests/validation_tests/commands.cc
+++ b/sandbox/win/tests/validation_tests/commands.cc
@@ -310,5 +310,24 @@
   return SBOX_TEST_SUCCEEDED;
 }
 
+SBOX_TESTS_COMMAND int AllocateCmd(int argc, wchar_t **argv) {
+  if (argc != 1)
+    return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
+
+  size_t mem_size = static_cast<size_t>(_wtoll(argv[0]));
+  void* memory = ::VirtualAlloc(NULL, mem_size, MEM_COMMIT | MEM_RESERVE,
+                                PAGE_READWRITE);
+  if (!memory) {
+    // We need to give the broker a chance to kill our process on failure.
+    ::Sleep(5000);
+    return SBOX_TEST_DENIED;
+  }
+
+  if (!::VirtualFree(memory, 0, MEM_RELEASE))
+    return SBOX_TEST_FAILED;
+
+  return SBOX_TEST_SUCCEEDED;
+}
+
 
 }  // namespace sandbox
diff --git a/sandbox/win/tests/validation_tests/suite.cc b/sandbox/win/tests/validation_tests/suite.cc
index f85b8da..4a8ae43 100644
--- a/sandbox/win/tests/validation_tests/suite.cc
+++ b/sandbox/win/tests/validation_tests/suite.cc
@@ -217,4 +217,25 @@
   EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(command));
 }
 
+// Tests if an over-limit allocation will be denied.
+TEST(ValidationSuite, TestMemoryLimit) {
+  TestRunner runner;
+  wchar_t command[1024] = {0};
+  const int kAllocationSize = 256 * 1024 * 1024;
+
+  wsprintf(command, L"AllocateCmd %d", kAllocationSize);
+  runner.GetPolicy()->SetJobMemoryLimit(kAllocationSize);
+  EXPECT_EQ(SBOX_FATAL_MEMORY_EXCEEDED, runner.RunTest(command));
+}
+
+// Tests a large allocation will succeed absent limits.
+TEST(ValidationSuite, TestMemoryNoLimit) {
+  TestRunner runner;
+  wchar_t command[1024] = {0};
+  const int kAllocationSize = 256 * 1024 * 1024;
+
+  wsprintf(command, L"AllocateCmd %d", kAllocationSize);
+  EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(command));
+}
+
 }  // namespace sandbox
diff --git a/sandbox/win/tests/validation_tests/unit_tests.cc b/sandbox/win/tests/validation_tests/unit_tests.cc
index 56be2ce..d3fd913 100644
--- a/sandbox/win/tests/validation_tests/unit_tests.cc
+++ b/sandbox/win/tests/validation_tests/unit_tests.cc
@@ -2,6 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "base/bind.h"
+#include "base/test/launcher/unit_test_launcher.h"
+#include "base/test/test_suite.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "sandbox/win/tests/common/controller.h"
 
@@ -11,6 +14,10 @@
       return sandbox::DispatchCall(argc, argv);
   }
 
-  testing::InitGoogleTest(&argc, argv);
-  return RUN_ALL_TESTS();
+  TestSuite test_suite(argc, argv);
+  return base::LaunchUnitTests(
+      argc,
+      argv,
+      false,
+      base::Bind(&base::TestSuite::Run, base::Unretained(&test_suite)));
 }