Bug 1530245 - Launch sandbox from new remote sandbox broker process. r=jld,bobowen
authorChris Pearce <cpearce@mozilla.com>
Wed, 13 Mar 2019 09:24:52 +0000
changeset 463798 64abd0254f73af2d4580b5ec7188f513a3fc785a
parent 463797 00fe102f6c0676cafce9859fa75a4e558b6e3661
child 463812 121d045e218a99cf425f243eb083d460c70a6e3a
push id80370
push usercpearce@mozilla.com
push dateWed, 13 Mar 2019 09:27:03 +0000
treeherderautoland@64abd0254f73 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjld, bobowen
bugs1530245
milestone67.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1530245 - Launch sandbox from new remote sandbox broker process. r=jld,bobowen Depends on D22051 Differential Revision: https://phabricator.services.mozilla.com/D22052
ipc/contentproc/plugin-container.cpp
ipc/glue/CrashReporterHost.cpp
ipc/glue/GeckoChildProcessHost.cpp
ipc/ipdl/sync-messages.ini
security/sandbox/moz.build
security/sandbox/win/src/remotesandboxbroker/PRemoteSandboxBroker.ipdl
security/sandbox/win/src/remotesandboxbroker/RemoteSandboxBrokerChild.cpp
security/sandbox/win/src/remotesandboxbroker/RemoteSandboxBrokerChild.h
security/sandbox/win/src/remotesandboxbroker/RemoteSandboxBrokerParent.cpp
security/sandbox/win/src/remotesandboxbroker/RemoteSandboxBrokerParent.h
security/sandbox/win/src/remotesandboxbroker/RemoteSandboxBrokerProcessChild.cpp
security/sandbox/win/src/remotesandboxbroker/RemoteSandboxBrokerProcessChild.h
security/sandbox/win/src/remotesandboxbroker/RemoteSandboxBrokerProcessParent.cpp
security/sandbox/win/src/remotesandboxbroker/RemoteSandboxBrokerProcessParent.h
security/sandbox/win/src/remotesandboxbroker/moz.build
security/sandbox/win/src/remotesandboxbroker/remoteSandboxBroker.cpp
security/sandbox/win/src/remotesandboxbroker/remoteSandboxBroker.h
security/sandbox/win/src/sandboxbroker/sandboxBroker.cpp
security/sandbox/win/src/sandboxbroker/sandboxBroker.h
toolkit/components/crashes/nsICrashService.idl
toolkit/xre/nsAppRunner.cpp
toolkit/xre/nsEmbedFunctions.cpp
xpcom/build/GeckoProcessTypes.h
xpcom/build/XREChildData.h
xpcom/components/nsComponentManager.cpp
xpcom/system/nsIXULRuntime.idl
--- a/ipc/contentproc/plugin-container.cpp
+++ b/ipc/contentproc/plugin-container.cpp
@@ -41,11 +41,18 @@ int content_process_main(mozilla::Bootst
     }
 
     childData.ProvideLogFunction = mozilla::sandboxing::ProvideLogFunction;
   }
 #endif
 
   bootstrap->XRE_SetProcessType(argv[--argc]);
 
+#if defined(XP_WIN) && defined(MOZ_SANDBOX)
+  if (bootstrap->XRE_GetProcessType() == GeckoProcessType_RemoteSandboxBroker) {
+    childData.sandboxBrokerServices =
+        mozilla::sandboxing::GetInitializedBrokerServices();
+  }
+#endif
+
   nsresult rv = bootstrap->XRE_InitChildProcess(argc, argv, &childData);
   return NS_FAILED(rv);
 }
--- a/ipc/glue/CrashReporterHost.cpp
+++ b/ipc/glue/CrashReporterHost.cpp
@@ -39,19 +39,22 @@ static_assert(nsICrashService::PROCESS_T
               "GeckoProcessType enum is out of sync with nsICrashService!");
 static_assert(nsICrashService::PROCESS_TYPE_VR == (int)GeckoProcessType_VR,
               "GeckoProcessType enum is out of sync with nsICrashService!");
 static_assert(nsICrashService::PROCESS_TYPE_RDD == (int)GeckoProcessType_RDD,
               "GeckoProcessType enum is out of sync with nsICrashService!");
 static_assert(nsICrashService::PROCESS_TYPE_SOCKET ==
                   (int)GeckoProcessType_Socket,
               "GeckoProcessType enum is out of sync with nsICrashService!");
+static_assert(nsICrashService::PROCESS_TYPE_SANDBOX_BROKER ==
+                  (int)GeckoProcessType_RemoteSandboxBroker,
+              "GeckoProcessType enum is out of sync with nsICrashService!");
 // Add new static asserts here if you add more process types.
 // Update this static assert as well.
-static_assert(nsICrashService::PROCESS_TYPE_SOCKET + 1 ==
+static_assert(nsICrashService::PROCESS_TYPE_SANDBOX_BROKER + 1 ==
                   (int)GeckoProcessType_End,
               "GeckoProcessType enum is out of sync with nsICrashService!");
 
 namespace mozilla {
 namespace ipc {
 
 CrashReporterHost::CrashReporterHost(GeckoProcessType aProcessType,
                                      const Shmem& aShmem,
--- a/ipc/glue/GeckoChildProcessHost.cpp
+++ b/ipc/glue/GeckoChildProcessHost.cpp
@@ -51,16 +51,19 @@
 #  include "nsIWinTaskbar.h"
 #  include <stdlib.h>
 #  define NS_TASKBAR_CONTRACTID "@mozilla.org/windows-taskbar;1"
 
 #  if defined(MOZ_SANDBOX)
 #    include "mozilla/Preferences.h"
 #    include "mozilla/sandboxing/sandboxLogging.h"
 #    include "WinUtils.h"
+#    if defined(_ARM64_)
+#      include "mozilla/remoteSandboxBroker.h"
+#    endif
 #  endif
 #endif
 
 #if defined(XP_LINUX) && defined(MOZ_SANDBOX)
 #  include "mozilla/SandboxLaunch.h"
 #endif
 
 #include "nsTArray.h"
@@ -98,17 +101,16 @@ GeckoChildProcessHost::GeckoChildProcess
       mIsFileContent(aIsFileContent),
       mMonitor("mozilla.ipc.GeckChildProcessHost.mMonitor"),
       mLaunchOptions(MakeUnique<base::LaunchOptions>()),
       mProcessState(CREATING_CHANNEL),
 #ifdef XP_WIN
       mGroupId(u"-"),
 #endif
 #if defined(MOZ_SANDBOX) && defined(XP_WIN)
-      mSandboxBroker(new SandboxBroker()),
       mEnableSandboxLogging(false),
       mSandboxLevel(0),
 #endif
       mChildProcessHandle(0),
 #if defined(MOZ_WIDGET_COCOA)
       mChildTask(MACH_PORT_NULL),
 #endif
       mDestroying(false) {
@@ -146,16 +148,22 @@ GeckoChildProcessHost::~GeckoChildProces
 #if defined(XP_WIN)
     CrashReporter::DeregisterChildCrashAnnotationFileDescriptor(
         base::GetProcId(mChildProcessHandle));
 #else
     CrashReporter::DeregisterChildCrashAnnotationFileDescriptor(
         mChildProcessHandle);
 #endif
   }
+#if defined(MOZ_SANDBOX) && defined(XP_WIN)
+  if (mSandboxBroker) {
+    mSandboxBroker->Shutdown();
+    mSandboxBroker = nullptr;
+  }
+#endif
 }
 
 void GeckoChildProcessHost::Destroy() {
   MOZ_RELEASE_ASSERT(!mDestroying);
   RefPtr<HandlePromise> whenReady = mHandlePromise;
 
   if (!whenReady) {
     // AsyncLaunch not called yet, so dispatch immediately.
@@ -1015,29 +1023,32 @@ bool GeckoChildProcessHost::PerformAsync
 #  endif  // MOZ_WIDGET_COCOA
 
 //--------------------------------------------------
 #elif defined(OS_WIN)  // defined(OS_POSIX)
 
   FilePath exePath;
   BinaryPathType pathType = GetPathToBinary(exePath, mProcessType);
 
-#  if defined(MOZ_SANDBOX) || (defined(_ARM64_) && defined(XP_WIN))
+#  if defined(MOZ_SANDBOX) || defined(_ARM64_)
   const bool isGMP = mProcessType == GeckoProcessType_GMPlugin;
   const bool isWidevine = isGMP && Contains(aExtraOpts, "gmp-widevinecdm");
-#    if defined(_ARM64_) && defined(XP_WIN)
+#    if defined(_ARM64_)
   const bool isClearKey = isGMP && Contains(aExtraOpts, "gmp-clearkey");
-  if (isGMP && (isClearKey || isWidevine)) {
-    // On Windows on ARM64 for ClearKey and Widevine, we want to run the
-    // x86 plugin-container.exe in the "i686" subdirectory, instead of the
-    // aarch64 plugin-container.exe. So insert "i686" into the exePath.
+  const bool isSandboxBroker =
+      mProcessType == GeckoProcessType_RemoteSandboxBroker;
+  if (isClearKey || isWidevine || isSandboxBroker) {
+    // On Windows on ARM64 for ClearKey and Widevine, and for the sandbox
+    // launcher process, we want to run the x86 plugin-container.exe in
+    // the "i686" subdirectory, instead of the aarch64 plugin-container.exe.
+    // So insert "i686" into the exePath.
     exePath = exePath.DirName().AppendASCII("i686").Append(exePath.BaseName());
   }
-#    endif
-#  endif  // defined(MOZ_SANDBOX) || (defined(_ARM64_) && defined(XP_WIN))
+#    endif  // if defined(_ARM64_)
+#  endif    // defined(MOZ_SANDBOX) || defined(_ARM64_)
 
   CommandLine cmdLine(exePath.ToWStringHack());
 
   if (pathType == BinaryPathType::Self) {
     cmdLine.AppendLooseValue(UTF8ToWide("-contentproc"));
   }
 
   cmdLine.AppendSwitchWithValue(switches::kProcessChannelID, channel_id());
@@ -1059,16 +1070,23 @@ bool GeckoChildProcessHost::PerformAsync
     file = Omnijar::GetPath(Omnijar::APP);
     if (file && NS_SUCCEEDED(file->GetPath(path))) {
       cmdLine.AppendLooseValue(UTF8ToWide("-appomni"));
       cmdLine.AppendLooseValue(path.get());
     }
   }
 
 #  if defined(MOZ_SANDBOX)
+#    if defined(_ARM64_)
+  if (isClearKey || isWidevine)
+    mSandboxBroker = new RemoteSandboxBroker();
+  else
+#    endif  // if defined(_ARM64_)
+    mSandboxBroker = new SandboxBroker();
+
   bool shouldSandboxCurrentProcess = false;
 
   // XXX: Bug 1124167: We should get rid of the process specific logic for
   // sandboxing in this class at some point. Unfortunately it will take a bit
   // of reorganizing so I don't think this patch is the right time.
   switch (mProcessType) {
     case GeckoProcessType_Content:
 #    if defined(MOZ_CONTENT_SANDBOX)
@@ -1131,16 +1149,19 @@ bool GeckoChildProcessHost::PerformAsync
           return false;
         }
         shouldSandboxCurrentProcess = true;
       }
       break;
     case GeckoProcessType_Socket:
       // TODO - setup sandboxing for the socket process.
       break;
+    case GeckoProcessType_RemoteSandboxBroker:
+      // We don't sandbox the sandbox launcher...
+      break;
     case GeckoProcessType_Default:
     default:
       MOZ_CRASH("Bad process type in GeckoChildProcessHost");
       break;
   };
 
   if (shouldSandboxCurrentProcess) {
     for (auto it = mAllowedFilesRead.begin(); it != mAllowedFilesRead.end();
@@ -1203,17 +1224,17 @@ bool GeckoChildProcessHost::PerformAsync
     switch (mProcessType) {
       case GeckoProcessType_Default:
         MOZ_CRASH("shouldn't be launching a parent process");
       case GeckoProcessType_Plugin:
       case GeckoProcessType_IPDLUnitTest:
         // No handle duplication necessary.
         break;
       default:
-        if (!mSandboxBroker->AddTargetPeer(process)) {
+        if (!SandboxBroker::AddTargetPeer(process)) {
           NS_WARNING("Failed to add child process as target peer.");
         }
         break;
     }
 #  endif  // MOZ_SANDBOX
   }
 
 #else  // goes with defined(OS_POSIX)
--- a/ipc/ipdl/sync-messages.ini
+++ b/ipc/ipdl/sync-messages.ini
@@ -1054,8 +1054,10 @@ description = bug 1382323
 [PHandlerService::Exists]
 description =
 [PHandlerService::GetTypeFromExtension]
 description =
 [PLayerTransaction::ShutdownSync]
 description = bug 1363126
 [PClientSource::WorkerSyncPing]
 description = Synchronous ping allowing worker thread to confirm actor is created. Necessary to avoid racing with ClientHandle actors on main thread.
+[PRemoteSandboxBroker::LaunchApp]
+description = Synchronous launch of a child process that in turn launches and sandboxes another process. Called on a dedicated thread and targets a dedicated process, so this shouldn't block anything.
--- a/security/sandbox/moz.build
+++ b/security/sandbox/moz.build
@@ -15,16 +15,17 @@ if CONFIG['OS_ARCH'] == 'Linux':
     DIRS += ['linux']
 elif CONFIG['OS_ARCH'] == 'Darwin':
     DIRS += ['mac']
 elif CONFIG['OS_ARCH'] == 'WINNT':
     Library('sandbox_s')
     FORCE_STATIC_LIB = True
 
     DIRS += [
+        'win/src/remotesandboxbroker',
         'win/src/sandboxbroker',
         'win/src/sandboxpermissions',
         'win/src/sandboxtarget',
     ]
 
     EXPORTS.mozilla.sandboxing += [
         'chromium-shim/sandbox/win/loggingCallbacks.h',
         'chromium-shim/sandbox/win/loggingTypes.h',
new file mode 100644
--- /dev/null
+++ b/security/sandbox/win/src/remotesandboxbroker/PRemoteSandboxBroker.ipdl
@@ -0,0 +1,35 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+using mozilla::dom::NativeThreadId from "mozilla/dom/TabMessageUtils.h";
+
+namespace mozilla {
+
+struct EnvVar {
+  nsString name;
+  nsString value;
+};
+
+struct LaunchParameters {
+  nsString path;
+  nsString args;
+  EnvVar[] env;
+  uint32_t processType;
+  uint32_t sandboxLevel;
+  nsString[] allowedReadFiles;
+  uint64_t[] shareHandles;
+  bool enableLogging;
+};
+
+intr protocol PRemoteSandboxBroker
+{
+parent:
+  async InitCrashReporter(Shmem shmem, NativeThreadId threadId);
+child:
+  intr LaunchApp(LaunchParameters params)
+    returns (bool ok, uint64_t handle);
+};
+
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/security/sandbox/win/src/remotesandboxbroker/RemoteSandboxBrokerChild.cpp
@@ -0,0 +1,86 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
+
+#include "RemoteSandboxBrokerChild.h"
+#include "mozilla/ipc/CrashReporterClient.h"
+#include "nsDebugImpl.h"
+#include "mozilla/ipc/CrashReporterClient.h"
+#include "RemoteSandboxBrokerProcessChild.h"
+
+using namespace mozilla::ipc;
+
+namespace mozilla {
+
+RemoteSandboxBrokerChild::RemoteSandboxBrokerChild() {
+  nsDebugImpl::SetMultiprocessMode("RemoteSandboxBroker");
+}
+
+RemoteSandboxBrokerChild::~RemoteSandboxBrokerChild() {}
+
+bool RemoteSandboxBrokerChild::Init(base::ProcessId aParentPid,
+                                    MessageLoop* aIOLoop,
+                                    IPC::Channel* aChannel) {
+  if (NS_WARN_IF(!Open(aChannel, aParentPid, aIOLoop))) {
+    return false;
+  }
+  CrashReporterClient::InitSingleton(this);
+  return true;
+}
+
+void RemoteSandboxBrokerChild::ActorDestroy(ActorDestroyReason aWhy) {
+  if (AbnormalShutdown == aWhy) {
+    NS_WARNING("Abnormal shutdown of GMP process!");
+    ipc::ProcessChild::QuickExit();
+  }
+  CrashReporterClient::DestroySingleton();
+  XRE_ShutdownChildProcess();
+}
+
+mozilla::ipc::IPCResult RemoteSandboxBrokerChild::AnswerLaunchApp(
+    LaunchParameters&& aParams, bool* aOutOk, uint64_t* aOutHandle) {
+  auto towstring = [](const nsString& s) {
+    return std::wstring(s.get(), s.Length());
+  };
+
+  base::EnvironmentMap envmap;
+  for (const EnvVar& env : aParams.env()) {
+    envmap[towstring(env.name())] = towstring(env.value());
+  }
+
+  if (!mSandboxBroker.SetSecurityLevelForGMPlugin(
+          AbstractSandboxBroker::SandboxLevel(aParams.sandboxLevel()))) {
+    *aOutOk = false;
+    return IPC_OK();
+  }
+
+  for (const auto& path : aParams.allowedReadFiles()) {
+    if (!mSandboxBroker.AllowReadFile(path.get())) {
+      *aOutOk = false;
+      return IPC_OK();
+    }
+  }
+
+  for (const auto& handle : aParams.shareHandles()) {
+    mSandboxBroker.AddHandleToShare(HANDLE(handle));
+  }
+
+  HANDLE p;
+  *aOutOk =
+      mSandboxBroker.LaunchApp(aParams.path().get(), aParams.args().get(),
+                               envmap, GeckoProcessType(aParams.processType()),
+                               aParams.enableLogging(), (void**)&p);
+  if (*aOutOk) {
+    *aOutHandle = uint64_t(p);
+  }
+
+  for (const auto& handle : aParams.shareHandles()) {
+    CloseHandle(HANDLE(handle));
+  }
+
+  return IPC_OK();
+}
+
+}  // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/security/sandbox/win/src/remotesandboxbroker/RemoteSandboxBrokerChild.h
@@ -0,0 +1,34 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
+
+#ifndef RemoteSandboxBrokerChild_h_
+#define RemoteSandboxBrokerChild_h_
+
+#include "mozilla/PRemoteSandboxBrokerChild.h"
+#include "sandboxBroker.h"
+
+namespace mozilla {
+
+class RemoteSandboxBrokerChild : public PRemoteSandboxBrokerChild {
+  friend class PRemoteSandboxBrokerChild;
+
+ public:
+  RemoteSandboxBrokerChild();
+  virtual ~RemoteSandboxBrokerChild();
+  bool Init(base::ProcessId aParentPid, MessageLoop* aIOLoop,
+            IPC::Channel* aChannel);
+
+ private:
+  mozilla::ipc::IPCResult AnswerLaunchApp(LaunchParameters&& aParams,
+                                          bool* aOutOk, uint64_t* aOutHandle);
+
+  void ActorDestroy(ActorDestroyReason aWhy);
+  SandboxBroker mSandboxBroker;
+};
+
+}  // namespace mozilla
+
+#endif
new file mode 100644
--- /dev/null
+++ b/security/sandbox/win/src/remotesandboxbroker/RemoteSandboxBrokerParent.cpp
@@ -0,0 +1,91 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
+
+#include "RemoteSandboxBrokerParent.h"
+#include "RemoteSandboxBrokerProcessParent.h"
+#include "mozilla/Telemetry.h"
+#include <windows.h>
+
+namespace mozilla {
+
+RefPtr<GenericPromise> RemoteSandboxBrokerParent::Launch(
+    const nsTArray<uint64_t>& aHandlesToShare) {
+  MOZ_ASSERT(!mProcess);
+  if (mProcess) {
+    // Don't re-init.
+    return GenericPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
+  }
+
+  mProcess = new RemoteSandboxBrokerProcessParent();
+  for (uint64_t handle : aHandlesToShare) {
+    mProcess->AddHandleToShare(HANDLE(handle));
+  }
+
+  // Note: we rely on the caller to keep this instance alive while we launch
+  // the process, so that these closures point to valid memory.
+  auto resolve = [this](base::ProcessHandle handle) {
+    mOpened = Open(mProcess->GetChannel(), base::GetProcId(handle));
+    if (!mOpened) {
+      mProcess->Destroy();
+      mProcess = nullptr;
+      return GenericPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
+    }
+    return GenericPromise::CreateAndResolve(true, __func__);
+  };
+
+  auto reject = [this]() {
+    NS_ERROR("failed to launch child in the parent");
+    if (mProcess) {
+      mProcess->Destroy();
+      mProcess = nullptr;
+    }
+    return GenericPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
+  };
+
+  return mProcess->AsyncLaunch()->Then(GetCurrentThreadSerialEventTarget(),
+                                       __func__, std::move(resolve),
+                                       std::move(reject));
+}
+
+bool RemoteSandboxBrokerParent::DuplicateFromLauncher(HANDLE aLauncherHandle,
+                                                      LPHANDLE aOurHandle) {
+  return ::DuplicateHandle(mProcess->GetChildProcessHandle(), aLauncherHandle,
+                           ::GetCurrentProcess(), aOurHandle, 0, false,
+                           DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
+}
+
+void RemoteSandboxBrokerParent::ActorDestroy(ActorDestroyReason aWhy) {
+  if (AbnormalShutdown == aWhy) {
+    Telemetry::Accumulate(Telemetry::SUBPROCESS_ABNORMAL_ABORT,
+                          NS_LITERAL_CSTRING("sandboxbroker"), 1);
+    if (mCrashReporter) {
+      mCrashReporter->GenerateCrashReport(OtherPid());
+      mCrashReporter = nullptr;
+    }
+  }
+  Shutdown();
+}
+
+void RemoteSandboxBrokerParent::Shutdown() {
+  if (mOpened) {
+    mOpened = false;
+    Close();
+  }
+  if (mProcess) {
+    mProcess->Destroy();
+    mProcess = nullptr;
+  }
+}
+
+mozilla::ipc::IPCResult RemoteSandboxBrokerParent::RecvInitCrashReporter(
+    Shmem&& aShmem, const NativeThreadId& aThreadId) {
+  mCrashReporter = MakeUnique<ipc::CrashReporterHost>(
+      GeckoProcessType_RemoteSandboxBroker, aShmem, aThreadId);
+
+  return IPC_OK();
+}
+
+}  // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/security/sandbox/win/src/remotesandboxbroker/RemoteSandboxBrokerParent.h
@@ -0,0 +1,43 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
+
+#ifndef RemoteSandboxBrokerParent_h_
+#define RemoteSandboxBrokerParent_h_
+
+#include "mozilla/PRemoteSandboxBrokerParent.h"
+#include "RemoteSandboxBrokerProcessParent.h"
+#include "mozilla/ipc/CrashReporterHost.h"
+
+namespace mozilla {
+
+class RemoteSandboxBrokerParent : public PRemoteSandboxBrokerParent {
+  friend class PRemoteSandboxBrokerParent;
+
+ public:
+  bool DuplicateFromLauncher(HANDLE aLauncherHandle, LPHANDLE aOurHandle);
+
+  void Shutdown();
+
+  // Asynchronously launches the launcher process.
+  // Note: we rely on the caller to keep this instance alive
+  // until this promise resolves.
+  RefPtr<GenericPromise> Launch(const nsTArray<uint64_t>& aHandlesToShare);
+
+ private:
+  mozilla::ipc::IPCResult RecvInitCrashReporter(
+      Shmem&& aShmem, const NativeThreadId& aThreadId);
+
+  void ActorDestroy(ActorDestroyReason aWhy) override;
+
+  RemoteSandboxBrokerProcessParent* mProcess = nullptr;
+
+  bool mOpened = false;
+  UniquePtr<ipc::CrashReporterHost> mCrashReporter;
+};
+
+}  // namespace mozilla
+
+#endif  // RemoteSandboxBrokerParent_h_
new file mode 100644
--- /dev/null
+++ b/security/sandbox/win/src/remotesandboxbroker/RemoteSandboxBrokerProcessChild.cpp
@@ -0,0 +1,32 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
+
+#include "RemoteSandboxBrokerProcessChild.h"
+
+#include "mozilla/ipc/IOThreadChild.h"
+#include "mozilla/BackgroundHangMonitor.h"
+
+using mozilla::ipc::IOThreadChild;
+
+namespace mozilla {
+
+RemoteSandboxBrokerProcessChild::RemoteSandboxBrokerProcessChild(
+    ProcessId aParentPid)
+    : ProcessChild(aParentPid) {}
+
+RemoteSandboxBrokerProcessChild::~RemoteSandboxBrokerProcessChild() {}
+
+bool RemoteSandboxBrokerProcessChild::Init(int aArgc, char* aArgv[]) {
+  BackgroundHangMonitor::Startup();
+  return mSandboxBrokerChild.Init(ParentPid(), IOThreadChild::message_loop(),
+                                  IOThreadChild::channel());
+}
+
+void RemoteSandboxBrokerProcessChild::CleanUp() {
+  BackgroundHangMonitor::Shutdown();
+}
+
+}  // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/security/sandbox/win/src/remotesandboxbroker/RemoteSandboxBrokerProcessChild.h
@@ -0,0 +1,33 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef RemoteSandboxBrokerProcessChild_h_
+#define RemoteSandboxBrokerProcessChild_h_
+
+#include "mozilla/ipc/ProcessChild.h"
+#include "RemoteSandboxBrokerChild.h"
+
+namespace mozilla {
+
+class RemoteSandboxBrokerProcessChild final
+    : public mozilla::ipc::ProcessChild {
+ protected:
+  typedef mozilla::ipc::ProcessChild ProcessChild;
+
+ public:
+  explicit RemoteSandboxBrokerProcessChild(ProcessId aParentPid);
+  ~RemoteSandboxBrokerProcessChild();
+
+  bool Init(int aArgc, char* aArgv[]) override;
+  void CleanUp() override;
+
+ private:
+  RemoteSandboxBrokerChild mSandboxBrokerChild;
+  DISALLOW_COPY_AND_ASSIGN(RemoteSandboxBrokerProcessChild);
+};
+
+}  // namespace mozilla
+
+#endif  // GMPProcessChild_h_
new file mode 100644
--- /dev/null
+++ b/security/sandbox/win/src/remotesandboxbroker/RemoteSandboxBrokerProcessParent.cpp
@@ -0,0 +1,33 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
+
+#include "RemoteSandboxBrokerProcessParent.h"
+#include "nsIRunnable.h"
+#include <windows.h>
+
+using mozilla::ipc::GeckoChildProcessHost;
+
+namespace mozilla {
+
+RemoteSandboxBrokerProcessParent::RemoteSandboxBrokerProcessParent()
+    : GeckoChildProcessHost(GeckoProcessType_RemoteSandboxBroker) {
+  MOZ_COUNT_CTOR(RemoteSandboxBrokerProcessParent);
+}
+
+RemoteSandboxBrokerProcessParent::~RemoteSandboxBrokerProcessParent() {
+  MOZ_COUNT_DTOR(RemoteSandboxBrokerProcessParent);
+}
+
+RefPtr<RemoteSandboxBrokerProcessParent::HandlePromise>
+RemoteSandboxBrokerProcessParent::AsyncLaunch() {
+  if (!GeckoChildProcessHost::AsyncLaunch()) {
+    return HandlePromise::CreateAndReject(GeckoChildProcessHost::LaunchError{},
+                                          __func__);
+  }
+  return WhenProcessHandleReady();
+}
+
+}  // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/security/sandbox/win/src/remotesandboxbroker/RemoteSandboxBrokerProcessParent.h
@@ -0,0 +1,46 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * vim: sw=2 ts=4 et :
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef RemoteSandboxBrokerProcessParent_h_
+#define RemoteSandboxBrokerProcessParent_h_
+
+#include "mozilla/Attributes.h"
+#include "base/basictypes.h"
+#include "base/file_path.h"
+#include "base/thread.h"
+#include "chrome/common/child_process_host.h"
+#include "mozilla/ipc/GeckoChildProcessHost.h"
+
+class nsIRunnable;
+
+namespace mozilla {
+
+class RemoteSandboxBrokerProcessParent final
+    : public mozilla::ipc::GeckoChildProcessHost {
+ public:
+  using LaunchError = GeckoChildProcessHost::LaunchError;
+  using LaunchPromise = GeckoChildProcessHost::LaunchPromise<bool>;
+
+  RemoteSandboxBrokerProcessParent();
+
+  using GeckoChildProcessHost::HandlePromise;
+
+  RefPtr<HandlePromise> AsyncLaunch();
+
+  bool CanShutdown() override { return true; }
+
+  using mozilla::ipc::GeckoChildProcessHost::GetChannel;
+  using mozilla::ipc::GeckoChildProcessHost::GetChildProcessHandle;
+
+ private:
+  ~RemoteSandboxBrokerProcessParent();
+
+  DISALLOW_COPY_AND_ASSIGN(RemoteSandboxBrokerProcessParent);
+};
+
+}  // namespace mozilla
+
+#endif  // ifndef GMPProcessParent_h
new file mode 100644
--- /dev/null
+++ b/security/sandbox/win/src/remotesandboxbroker/moz.build
@@ -0,0 +1,35 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+SOURCES += [
+    'remoteSandboxBroker.cpp',
+    'RemoteSandboxBrokerChild.cpp',
+    'RemoteSandboxBrokerParent.cpp',
+    'RemoteSandboxBrokerProcessChild.cpp',
+    'RemoteSandboxBrokerProcessParent.cpp',
+]
+
+EXPORTS.mozilla += [
+    'remoteSandboxBroker.h',
+    'RemoteSandboxBrokerChild.h',
+    'RemoteSandboxBrokerParent.h',
+    'RemoteSandboxBrokerProcessChild.h',
+    'RemoteSandboxBrokerProcessParent.h',
+]
+
+for var in ('UNICODE', '_UNICODE'):
+    DEFINES[var] = True
+
+FINAL_LIBRARY = 'xul'
+
+if CONFIG['CC_TYPE'] == 'clang-cl':
+    AllowCompilerWarnings()  # workaround for bug 1090497
+
+IPDL_SOURCES += [
+  'PRemoteSandboxBroker.ipdl'
+]
+
+include('/ipc/chromium/chromium-config.mozbuild')
new file mode 100644
--- /dev/null
+++ b/security/sandbox/win/src/remotesandboxbroker/remoteSandboxBroker.cpp
@@ -0,0 +1,159 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
+
+#include "remoteSandboxBroker.h"
+
+namespace mozilla {
+
+RemoteSandboxBroker::RemoteSandboxBroker() {}
+
+RemoteSandboxBroker::~RemoteSandboxBroker() {
+  MOZ_ASSERT(
+      mShutdown,
+      "Shutdown must be called on RemoteSandboxBroker before destruction!");
+}
+
+void RemoteSandboxBroker::Shutdown() {
+  MOZ_ASSERT(!mShutdown, "Don't call Shutdown() twice!");
+  mShutdown = true;
+
+  if (!mIPCLaunchThread) {
+    // Can't have launched child process, nothing to shutdown.
+    return;
+  }
+
+  RefPtr<RemoteSandboxBroker> self = this;
+  mIPCLaunchThread->Dispatch(
+      NS_NewRunnableFunction("Remote Sandbox Launch", [self, this]() {
+        // Note: `self` here should be the last reference to this instance.
+        mParent.Shutdown();
+        mIPCLaunchThread = nullptr;
+      }));
+}
+
+bool RemoteSandboxBroker::LaunchApp(const wchar_t *aPath,
+                                    const wchar_t *aArguments,
+                                    base::EnvironmentMap &aEnvironment,
+                                    GeckoProcessType aProcessType,
+                                    const bool aEnableLogging,
+                                    void **aProcessHandle) {
+  // Note: we expect to be called on the IPC launch thread from
+  // GeckoChildProcesHost while it's launching a child process. We can't
+  // run a synchronous launch here as that blocks the calling thread while
+  // it dispatches a task to the IPC launch thread to spawn the process.
+  // Since our calling thread is the IPC launch thread, we'd then be
+  // deadlocked. So instead we do an async launch, and spin the event
+  // loop until the process launch succeeds.
+
+  // We should be on the IPC launch thread. We're shutdown on the IO thread,
+  // so save a ref to the IPC launch thread here, so we can close the channel
+  // on the IPC launch thread on shutdown.
+  mIPCLaunchThread = GetCurrentThreadEventTarget();
+
+  mParameters.path() = nsDependentString(aPath);
+  mParameters.args() = nsDependentString(aArguments);
+
+  auto toNsString = [](const std::wstring &s) {
+    return nsDependentString(s.c_str());
+  };
+  for (auto itr : aEnvironment) {
+    mParameters.env().AppendElement(
+        EnvVar(toNsString(itr.first), toNsString(itr.second)));
+  }
+
+  mParameters.processType() = uint32_t(aProcessType);
+  mParameters.enableLogging() = aEnableLogging;
+
+  enum Result { Pending, Succeeded, Failed };
+  Result res = Pending;
+  auto resolve = [&](bool ok) {
+    res = Succeeded;
+    return GenericPromise::CreateAndResolve(ok, __func__);
+  };
+
+  auto reject = [&](nsresult) {
+    res = Failed;
+    return GenericPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
+  };
+
+  mParent.Launch(mParameters.shareHandles())
+      ->Then(GetCurrentThreadSerialEventTarget(), __func__, std::move(resolve),
+             std::move(reject));
+
+  // Spin the event loop while the sandbox launcher process launches.
+  SpinEventLoopUntil([&]() { return res != Pending; });
+
+  if (res == Failed) {
+    return false;
+  }
+
+  uint64_t handle = 0;
+  bool ok = false;
+  bool rv = mParent.CallLaunchApp(std::move(mParameters), &ok, &handle) && ok;
+  mParameters.shareHandles().Clear();
+  if (!rv) {
+    return false;
+  }
+
+  // Duplicate the handle of the child process that the launcher launched from
+  // the launcher process's space into this process' space.
+  HANDLE ourChildHandle = 0;
+  bool dh = mParent.DuplicateFromLauncher((HANDLE)handle, &ourChildHandle);
+  if (!dh) {
+    return false;
+  }
+
+  *aProcessHandle = (void **)(ourChildHandle);
+
+  base::ProcessHandle process = *aProcessHandle;
+  SandboxBroker::AddTargetPeer(process);
+
+  return true;
+}
+
+bool RemoteSandboxBroker::SetSecurityLevelForGMPlugin(SandboxLevel aLevel) {
+  mParameters.sandboxLevel() = uint32_t(aLevel);
+  return true;
+}
+
+bool RemoteSandboxBroker::AllowReadFile(wchar_t const *aFile) {
+  mParameters.allowedReadFiles().AppendElement(nsDependentString(aFile));
+  return true;
+}
+
+void RemoteSandboxBroker::AddHandleToShare(HANDLE aHandle) {
+  mParameters.shareHandles().AppendElement(uint64_t(aHandle));
+}
+
+#ifdef MOZ_CONTENT_SANDBOX
+void RemoteSandboxBroker::SetSecurityLevelForContentProcess(
+    int32_t aSandboxLevel, bool aIsFileProcess) {
+  MOZ_CRASH(
+      "RemoteSandboxBroker::SetSecurityLevelForContentProcess not Implemented");
+}
+#endif
+
+void RemoteSandboxBroker::SetSecurityLevelForGPUProcess(int32_t aSandboxLevel) {
+  MOZ_CRASH(
+      "RemoteSandboxBroker::SetSecurityLevelForGPUProcess not Implemented");
+}
+
+bool RemoteSandboxBroker::SetSecurityLevelForRDDProcess() {
+  MOZ_CRASH(
+      "RemoteSandboxBroker::SetSecurityLevelForRDDProcess not Implemented");
+}
+
+bool RemoteSandboxBroker::SetSecurityLevelForPluginProcess(
+    int32_t aSandboxLevel) {
+  MOZ_CRASH(
+      "RemoteSandboxBroker::SetSecurityLevelForPluginProcess not Implemented");
+}
+
+AbstractSandboxBroker *CreateRemoteSandboxBroker() {
+  return new RemoteSandboxBroker();
+}
+
+}  // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/security/sandbox/win/src/remotesandboxbroker/remoteSandboxBroker.h
@@ -0,0 +1,66 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
+
+#ifndef __REMOTE_SANDBOXBROKER_H__
+#define __REMOTE_SANDBOXBROKER_H__
+
+#include "sandboxBroker.h"
+#include "RemoteSandboxBrokerParent.h"
+
+namespace mozilla {
+
+// To make sandboxing an x86 plugin-container process on Windows on ARM64,
+// we launch an x86 child process which in turn launches and sandboxes the x86
+// plugin-container child. This means the sandbox broker (in the remote
+// x86 sandbox launcher process) can be same-arch with the process that it's
+// sandboxing, which means all the sandbox's assumptions about things being
+// same arch still hold.
+class RemoteSandboxBroker : public AbstractSandboxBroker {
+ public:
+  RemoteSandboxBroker();
+
+  void Shutdown() override;
+
+  // Note: This should be called on the IPC launch thread, and this spins
+  // the event loop. So this means potentially another IPC launch could occur
+  // re-entrantly while calling this.
+  bool LaunchApp(const wchar_t *aPath, const wchar_t *aArguments,
+                 base::EnvironmentMap &aEnvironment,
+                 GeckoProcessType aProcessType, const bool aEnableLogging,
+                 void **aProcessHandle) override;
+
+  // Security levels for different types of processes
+#if defined(MOZ_CONTENT_SANDBOX)
+  void SetSecurityLevelForContentProcess(int32_t aSandboxLevel,
+                                         bool aIsFileProcess) override;
+#endif
+  void SetSecurityLevelForGPUProcess(int32_t aSandboxLevel) override;
+  bool SetSecurityLevelForRDDProcess() override;
+  bool SetSecurityLevelForPluginProcess(int32_t aSandboxLevel) override;
+  bool SetSecurityLevelForGMPlugin(SandboxLevel aLevel) override;
+  bool AllowReadFile(wchar_t const *file) override;
+  void AddHandleToShare(HANDLE aHandle) override;
+
+ private:
+  virtual ~RemoteSandboxBroker();
+
+  // Parameters that we use to launch the child process.
+  LaunchParameters mParameters;
+
+  RemoteSandboxBrokerParent mParent;
+
+  // We bind the RemoteSandboxBrokerParent to the IPC launch thread.
+  // As such, we must close its channel on the same thread. So we save
+  // a reference to the IPC launch thread here.
+  nsCOMPtr<nsIEventTarget> mIPCLaunchThread;
+
+  // True if we've been shutdown.
+  bool mShutdown = false;
+};
+
+}  // namespace mozilla
+
+#endif  // __REMOTE_SANDBOXBROKER_H__
--- a/security/sandbox/win/src/sandboxbroker/sandboxBroker.cpp
+++ b/security/sandbox/win/src/sandboxbroker/sandboxBroker.cpp
@@ -92,53 +92,64 @@ static void CacheDirAndAutoClear(nsIProp
     (*cacheVar)->InsertLiteral(u"??\\UNC", 1);
   }
 }
 
 /* static */
 void SandboxBroker::GeckoDependentInitialize() {
   MOZ_ASSERT(NS_IsMainThread());
 
-  // Cache directory paths for use in policy rules, because the directory
-  // service must be called on the main thread.
-  nsresult rv;
-  nsCOMPtr<nsIProperties> dirSvc =
-      do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID, &rv);
-  if (NS_FAILED(rv)) {
-    MOZ_ASSERT(
-        false,
-        "Failed to get directory service, cannot cache directories for rules.");
-    LOG_E(
-        "Failed to get directory service, cannot cache directories for rules.");
-    return;
+  bool haveXPCOM = XRE_GetProcessType() != GeckoProcessType_RemoteSandboxBroker;
+  if (haveXPCOM) {
+    // Cache directory paths for use in policy rules, because the directory
+    // service must be called on the main thread.
+    nsresult rv;
+    nsCOMPtr<nsIProperties> dirSvc =
+        do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID, &rv);
+    if (NS_FAILED(rv)) {
+      MOZ_ASSERT(false,
+                 "Failed to get directory service, cannot cache directories "
+                 "for rules.");
+      LOG_E(
+          "Failed to get directory service, cannot cache directories for "
+          "rules.");
+      return;
+    }
+
+    CacheDirAndAutoClear(dirSvc, NS_GRE_DIR, &sBinDir);
+    CacheDirAndAutoClear(dirSvc, NS_APP_USER_PROFILE_50_DIR, &sProfileDir);
+    CacheDirAndAutoClear(dirSvc, NS_APP_CONTENT_PROCESS_TEMP_DIR,
+                         &sContentTempDir);
+    CacheDirAndAutoClear(dirSvc, NS_APP_PLUGIN_PROCESS_TEMP_DIR,
+                         &sPluginTempDir);
+    CacheDirAndAutoClear(dirSvc, NS_WIN_APPDATA_DIR, &sRoamingAppDataDir);
+    CacheDirAndAutoClear(dirSvc, NS_WIN_LOCAL_APPDATA_DIR, &sLocalAppDataDir);
+    CacheDirAndAutoClear(dirSvc, XRE_USER_SYS_EXTENSION_DEV_DIR,
+                         &sUserExtensionsDevDir);
+#ifdef ENABLE_SYSTEM_EXTENSION_DIRS
+    CacheDirAndAutoClear(dirSvc, XRE_USER_SYS_EXTENSION_DIR,
+                         &sUserExtensionsDir);
+#endif
   }
 
-  CacheDirAndAutoClear(dirSvc, NS_GRE_DIR, &sBinDir);
-  CacheDirAndAutoClear(dirSvc, NS_APP_USER_PROFILE_50_DIR, &sProfileDir);
-  CacheDirAndAutoClear(dirSvc, NS_APP_CONTENT_PROCESS_TEMP_DIR,
-                       &sContentTempDir);
-  CacheDirAndAutoClear(dirSvc, NS_APP_PLUGIN_PROCESS_TEMP_DIR, &sPluginTempDir);
-  CacheDirAndAutoClear(dirSvc, NS_WIN_APPDATA_DIR, &sRoamingAppDataDir);
-  CacheDirAndAutoClear(dirSvc, NS_WIN_LOCAL_APPDATA_DIR, &sLocalAppDataDir);
-  CacheDirAndAutoClear(dirSvc, XRE_USER_SYS_EXTENSION_DEV_DIR,
-                       &sUserExtensionsDevDir);
-#ifdef ENABLE_SYSTEM_EXTENSION_DIRS
-  CacheDirAndAutoClear(dirSvc, XRE_USER_SYS_EXTENSION_DIR, &sUserExtensionsDir);
-#endif
-
   // Create sLaunchErrors up front because ClearOnShutdown must be called on the
   // main thread.
   sLaunchErrors = MakeUnique<nsTHashtable<nsCStringHashKey>>();
   ClearOnShutdown(&sLaunchErrors);
 
-  // Cache prefs that are needed off main thread.
-  Preferences::AddBoolVarCache(&sRddWin32kDisable,
-                               "security.sandbox.rdd.win32k-disable");
-  Preferences::AddBoolVarCache(&sGmpWin32kDisable,
-                               "security.sandbox.gmp.win32k-disable");
+  if (haveXPCOM) {
+    // Cache prefs that are needed off main thread.
+    Preferences::AddBoolVarCache(&sRddWin32kDisable,
+                                 "security.sandbox.rdd.win32k-disable");
+    Preferences::AddBoolVarCache(&sGmpWin32kDisable,
+                                 "security.sandbox.gmp.win32k-disable");
+  } else {
+    sRddWin32kDisable = false;
+    sGmpWin32kDisable = false;
+  }
 }
 
 SandboxBroker::SandboxBroker() {
   if (sBrokerService) {
     scoped_refptr<sandbox::TargetPolicy> policy =
         sBrokerService->CreatePolicy();
     mPolicy = policy.get();
     mPolicy->AddRef();
@@ -1159,16 +1170,17 @@ bool SandboxBroker::AllowReadFile(wchar_
   if (sandbox::SBOX_ALL_OK != result) {
     LOG_E("Failed (ResultCode %d) to add read access to: %S", result, file);
     return false;
   }
 
   return true;
 }
 
+/* static */
 bool SandboxBroker::AddTargetPeer(HANDLE aPeerProcess) {
   if (!sBrokerService) {
     return false;
   }
 
   sandbox::ResultCode result = sBrokerService->AddTargetPeer(aPeerProcess);
   return (sandbox::SBOX_ALL_OK == result);
 }
@@ -1199,9 +1211,27 @@ void SandboxBroker::ApplyLoggingPolicy()
 
 SandboxBroker::~SandboxBroker() {
   if (mPolicy) {
     mPolicy->Release();
     mPolicy = nullptr;
   }
 }
 
+#ifdef _ARM64_
+// We can't include remoteSandboxBroker.h here directly, as it includes
+// IPDL headers, which include a different copy of the chromium base
+// libraries, which leads to conflicts.
+extern AbstractSandboxBroker* CreateRemoteSandboxBroker();
+#endif
+
+// static
+AbstractSandboxBroker* AbstractSandboxBroker::Create(
+    GeckoProcessType aProcessType) {
+#ifdef _ARM64_
+  if (aProcessType == GeckoProcessType_GMPlugin) {
+    return CreateRemoteSandboxBroker();
+  }
+#endif
+  return new SandboxBroker();
+}
+
 }  // namespace mozilla
--- a/security/sandbox/win/src/sandboxbroker/sandboxBroker.h
+++ b/security/sandbox/win/src/sandboxbroker/sandboxBroker.h
@@ -21,16 +21,19 @@ class TargetPolicy;
 }  // namespace sandbox
 
 namespace mozilla {
 
 class AbstractSandboxBroker {
  public:
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(AbstractSandboxBroker)
 
+  static AbstractSandboxBroker *Create(GeckoProcessType aProcessType);
+
+  virtual void Shutdown() = 0;
   virtual bool LaunchApp(const wchar_t *aPath, const wchar_t *aArguments,
                          base::EnvironmentMap &aEnvironment,
                          GeckoProcessType aProcessType,
                          const bool aEnableLogging, void **aProcessHandle) = 0;
 
   // Security levels for different types of processes
 #if defined(MOZ_CONTENT_SANDBOX)
   virtual void SetSecurityLevelForContentProcess(int32_t aSandboxLevel,
@@ -43,22 +46,16 @@ class AbstractSandboxBroker {
   virtual bool SetSecurityLevelForPluginProcess(int32_t aSandboxLevel) = 0;
   enum SandboxLevel { LockDown, Restricted };
   virtual bool SetSecurityLevelForGMPlugin(SandboxLevel aLevel) = 0;
 
   // File system permissions
   virtual bool AllowReadFile(wchar_t const *file) = 0;
 
   /**
-   * Exposes AddTargetPeer from broker services, so that non-sandboxed
-   * processes can be added as handle duplication targets.
-   */
-  virtual bool AddTargetPeer(HANDLE aPeerProcess) = 0;
-
-  /**
    * Share a HANDLE with the child process. The HANDLE will be made available
    * in the child process at the memory address
    * |reinterpret_cast<uintptr_t>(aHandle)|. It is the caller's responsibility
    * to communicate this address to the child.
    */
   virtual void AddHandleToShare(HANDLE aHandle) = 0;
 
  protected:
@@ -66,16 +63,18 @@ class AbstractSandboxBroker {
 };
 
 class SandboxBroker : public AbstractSandboxBroker {
  public:
   SandboxBroker();
 
   static void Initialize(sandbox::BrokerServices *aBrokerServices);
 
+  void Shutdown() override {}
+
   /**
    * Do initialization that depends on parts of the Gecko machinery having been
    * created first.
    */
   static void GeckoDependentInitialize();
 
   bool LaunchApp(const wchar_t *aPath, const wchar_t *aArguments,
                  base::EnvironmentMap &aEnvironment,
@@ -97,17 +96,17 @@ class SandboxBroker : public AbstractSan
 
   // File system permissions
   bool AllowReadFile(wchar_t const *file) override;
 
   /**
    * Exposes AddTargetPeer from broker services, so that non-sandboxed
    * processes can be added as handle duplication targets.
    */
-  bool AddTargetPeer(HANDLE aPeerProcess) override;
+  static bool AddTargetPeer(HANDLE aPeerProcess);
 
   /**
    * Share a HANDLE with the child process. The HANDLE will be made available
    * in the child process at the memory address
    * |reinterpret_cast<uintptr_t>(aHandle)|. It is the caller's responsibility
    * to communicate this address to the child.
    */
   void AddHandleToShare(HANDLE aHandle) override;
--- a/toolkit/components/crashes/nsICrashService.idl
+++ b/toolkit/components/crashes/nsICrashService.idl
@@ -1,15 +1,15 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsISupports.idl"
 
-[scriptable, uuid(f60d76e5-62c3-4f58-89f6-b726c2b7bc20)]
+[scriptable, uuid(70bd93ff-88fa-4600-8af8-57c8d002dbac)]
 interface nsICrashService : nsISupports
 {
   /**
    * Records the occurrence of a crash.
    *
    * @param processType
    *        One of the PROCESS_TYPE constants defined below.
    * @param crashType
@@ -25,13 +25,14 @@ interface nsICrashService : nsISupports
   const long PROCESS_TYPE_PLUGIN = 1;
   const long PROCESS_TYPE_CONTENT = 2;
   const long PROCESS_TYPE_IPDLUNITTEST = 3;
   const long PROCESS_TYPE_GMPLUGIN = 4;
   const long PROCESS_TYPE_GPU = 5;
   const long PROCESS_TYPE_VR = 6;
   const long PROCESS_TYPE_RDD = 7;
   const long PROCESS_TYPE_SOCKET = 8;
+  const long PROCESS_TYPE_SANDBOX_BROKER = 9;
   // New process types should be added at the end of the above list.
 
   const long CRASH_TYPE_CRASH = 0;
   const long CRASH_TYPE_HANG = 1;
 };
--- a/toolkit/xre/nsAppRunner.cpp
+++ b/toolkit/xre/nsAppRunner.cpp
@@ -626,19 +626,20 @@ SYNC_ENUMS(DEFAULT, Default)
 SYNC_ENUMS(PLUGIN, Plugin)
 SYNC_ENUMS(CONTENT, Content)
 SYNC_ENUMS(IPDLUNITTEST, IPDLUnitTest)
 SYNC_ENUMS(GMPLUGIN, GMPlugin)
 SYNC_ENUMS(GPU, GPU)
 SYNC_ENUMS(VR, VR)
 SYNC_ENUMS(RDD, RDD)
 SYNC_ENUMS(SOCKET, Socket)
+SYNC_ENUMS(SANDBOX_BROKER, RemoteSandboxBroker)
 
 // .. and ensure that that is all of them:
-static_assert(GeckoProcessType_Socket + 1 == GeckoProcessType_End,
+static_assert(GeckoProcessType_RemoteSandboxBroker + 1 == GeckoProcessType_End,
               "Did not find the final GeckoProcessType");
 
 NS_IMETHODIMP
 nsXULAppInfo::GetProcessType(uint32_t* aResult) {
   NS_ENSURE_ARG_POINTER(aResult);
   *aResult = XRE_GetProcessType();
   return NS_OK;
 }
@@ -1530,21 +1531,21 @@ static void RegisterApplicationRestartCh
 
 #  if defined(MOZ_LAUNCHER_PROCESS)
 
 static const char kShieldPrefName[] = "app.shield.optoutstudies.enabled";
 
 static void OnLauncherPrefChanged(const char* aPref, void* aData) {
   const bool kLauncherPrefDefaultValue =
 #    if defined(NIGHTLY_BUILD) || (MOZ_UPDATE_CHANNEL == beta)
-    true
+      true
 #    else
-    false
+      false
 #    endif  // defined(NIGHTLY_BUILD) || (MOZ_UPDATE_CHANNEL == beta)
-    ;
+      ;
   bool prefVal = Preferences::GetBool(kShieldPrefName, false) &&
                  Preferences::GetBool(PREF_WIN_LAUNCHER_PROCESS_ENABLED,
                                       kLauncherPrefDefaultValue);
 
   mozilla::LauncherRegistryInfo launcherRegInfo;
   mozilla::LauncherVoidResult reflectResult =
       launcherRegInfo.ReflectPrefToRegistry(prefVal);
   MOZ_ASSERT(reflectResult.isOk());
--- a/toolkit/xre/nsEmbedFunctions.cpp
+++ b/toolkit/xre/nsEmbedFunctions.cpp
@@ -86,16 +86,17 @@
 #include "mozilla/gfx/GPUProcessImpl.h"
 #include "mozilla/net/SocketProcessImpl.h"
 
 #include "GeckoProfiler.h"
 
 #if defined(MOZ_SANDBOX) && defined(XP_WIN)
 #  include "mozilla/sandboxTarget.h"
 #  include "mozilla/sandboxing/loggingCallbacks.h"
+#  include "mozilla/RemoteSandboxBrokerProcessChild.h"
 #endif
 
 #if defined(MOZ_CONTENT_SANDBOX)
 #  include "mozilla/SandboxSettings.h"
 #  include "mozilla/Preferences.h"
 #endif
 
 #if defined(XP_LINUX) && defined(MOZ_SANDBOX)
@@ -118,16 +119,21 @@
 
 using mozilla::_ipdltest::IPDLUnitTestProcessChild;
 #endif  // ifdef MOZ_IPDL_TESTS
 
 #ifdef MOZ_JPROF
 #  include "jprof.h"
 #endif
 
+#if defined(XP_WIN) && defined(MOZ_SANDBOX)
+#  include "mozilla/sandboxing/SandboxInitialization.h"
+#  include "mozilla/sandboxing/sandboxLogging.h"
+#endif
+
 #include "VRProcessChild.h"
 
 using namespace mozilla;
 
 using mozilla::ipc::BrowserProcessSubThread;
 using mozilla::ipc::GeckoChildProcessHost;
 using mozilla::ipc::IOThreadChild;
 using mozilla::ipc::ProcessChild;
@@ -641,23 +647,31 @@ nsresult XRE_InitChildProcess(int aArgc,
     case GeckoProcessType_GPU:
     case GeckoProcessType_VR:
     case GeckoProcessType_RDD:
     case GeckoProcessType_Socket:
       // Content processes need the XPCOM/chromium frankenventloop
       uiLoopType = MessageLoop::TYPE_MOZILLA_CHILD;
       break;
     case GeckoProcessType_GMPlugin:
+    case GeckoProcessType_RemoteSandboxBroker:
       uiLoopType = MessageLoop::TYPE_DEFAULT;
       break;
     default:
       uiLoopType = MessageLoop::TYPE_UI;
       break;
   }
 
+#if defined(MOZ_SANDBOX) && defined(XP_WIN)
+  if (aChildData->sandboxBrokerServices) {
+    SandboxBroker::Initialize(aChildData->sandboxBrokerServices);
+    SandboxBroker::GeckoDependentInitialize();
+  }
+#endif
+
   // If we are recording or replaying, initialize state and update arguments
   // according to those which were captured by the MiddlemanProcessChild in the
   // middleman process. No argument manipulation should happen between this
   // call and the point where the process child is initialized.
   recordreplay::child::InitRecordingOrReplayingProcess(&aArgc, &aArgv);
 
   {
     // This is a lexical scope for the MessageLoop below.  We want it
@@ -710,16 +724,21 @@ nsresult XRE_InitChildProcess(int aArgc,
         case GeckoProcessType_RDD:
           process = new RDDProcessImpl(parentPID);
           break;
 
         case GeckoProcessType_Socket:
           process = new net::SocketProcessImpl(parentPID);
           break;
 
+#if defined(MOZ_SANDBOX) && defined(XP_WIN)
+        case GeckoProcessType_RemoteSandboxBroker:
+          process = new RemoteSandboxBrokerProcessChild(parentPID);
+          break;
+#endif
         default:
           MOZ_CRASH("Unknown main thread class");
       }
 
       if (!process->Init(aArgc, aArgv)) {
         return NS_ERROR_FAILURE;
       }
 
@@ -731,20 +750,23 @@ nsresult XRE_InitChildProcess(int aArgc,
 #endif
 
 #if defined(MOZ_SANDBOX) && defined(XP_WIN)
       // We need to do this after the process has been initialised, as
       // InitLoggingIfRequired may need access to prefs.
       mozilla::sandboxing::InitLoggingIfRequired(
           aChildData->ProvideLogFunction);
 #endif
-      mozilla::FilePreferences::InitDirectoriesWhitelist();
-      mozilla::FilePreferences::InitPrefs();
-
-      OverrideDefaultLocaleIfNeeded();
+      if (XRE_GetProcessType() != GeckoProcessType_RemoteSandboxBroker) {
+        // Remote sandbox launcher process doesn't have prerequisites for
+        // these...
+        mozilla::FilePreferences::InitDirectoriesWhitelist();
+        mozilla::FilePreferences::InitPrefs();
+        OverrideDefaultLocaleIfNeeded();
+      }
 
 #if defined(MOZ_CONTENT_SANDBOX)
       AddContentSandboxLevelAnnotation();
 #endif
 
       // Run the UI event loop on the main thread.
       uiMessageLoop.MessageLoop::Run();
 
--- a/xpcom/build/GeckoProcessTypes.h
+++ b/xpcom/build/GeckoProcessTypes.h
@@ -23,8 +23,9 @@ GECKO_PROCESS_TYPE(GMPlugin, "gmplugin",
 // GPU and compositor process.
 GECKO_PROCESS_TYPE(GPU, "gpu", GPU)
 // VR process.
 GECKO_PROCESS_TYPE(VR, "vr", VR)
 // Remote Data Decoder process.
 GECKO_PROCESS_TYPE(RDD, "rdd", RDD)
 // Socket process
 GECKO_PROCESS_TYPE(Socket, "socket", Socket)
+GECKO_PROCESS_TYPE(RemoteSandboxBroker, "sandbox", RemoteSandboxBroker)
--- a/xpcom/build/XREChildData.h
+++ b/xpcom/build/XREChildData.h
@@ -26,12 +26,18 @@ struct XREChildData {
    * Chromium sandbox TargetServices.
    */
   sandbox::TargetServices* sandboxTargetServices = nullptr;
 
   /**
    * Function to provide a logging function to the chromium sandbox code.
    */
   mozilla::sandboxing::ProvideLogFunctionCb ProvideLogFunction = nullptr;
+
+  /**
+   * Chromium sandbox broker services; needed by the remote sandbox
+   * launcher process.
+   */
+  sandbox::BrokerServices* sandboxBrokerServices = nullptr;
 #endif
 };
 
 #endif  // XREChildData_h
--- a/xpcom/components/nsComponentManager.cpp
+++ b/xpcom/components/nsComponentManager.cpp
@@ -507,16 +507,17 @@ nsresult nsComponentManagerImpl::Init() 
     }
   }
 
   bool loadChromeManifests;
   switch (XRE_GetProcessType()) {
     // We are going to assume that only a select few (see below) process types
     // want to load chrome manifests, and that any new process types will not
     // want to load them, because they're not going to be executing JS.
+    case GeckoProcessType_RemoteSandboxBroker:
     default:
       loadChromeManifests = false;
       break;
 
     // XXX The check this code replaced implicitly let through all of these
     // process types, but presumably only the default (parent) and content
     // processes really need chrome manifests...?
     case GeckoProcessType_Default:
--- a/xpcom/system/nsIXULRuntime.idl
+++ b/xpcom/system/nsIXULRuntime.idl
@@ -74,16 +74,17 @@ interface nsIXULRuntime : nsISupports
   const unsigned long PROCESS_TYPE_PLUGIN = 1;
   const unsigned long PROCESS_TYPE_CONTENT = 2;
   const unsigned long PROCESS_TYPE_IPDLUNITTEST = 3;
   const unsigned long PROCESS_TYPE_GMPLUGIN = 4;
   const unsigned long PROCESS_TYPE_GPU = 5;
   const unsigned long PROCESS_TYPE_VR = 6;
   const unsigned long PROCESS_TYPE_RDD = 7;
   const unsigned long PROCESS_TYPE_SOCKET = 8;
+  const unsigned long PROCESS_TYPE_SANDBOX_BROKER = 9;
 
   /**
    * The type of the caller's process.  Returns one of the values above.
    */
   readonly attribute unsigned long processType;
 
   /**
    * The system process ID of the caller's process.