Bug 1498742 - Part 2 - Start the GMP sandbox earlier during process startup r=jya,cpearce
☠☠ backed out by bd204c2146f2 ☠ ☠
authorHaik Aftandilian <haftandilian@mozilla.com>
Fri, 14 Jun 2019 20:12:01 +0000
changeset 538571 f6da94d9035047b44f1521bfd2d37960263a2f36
parent 538570 4f3e83d8de597e423227162b9b54d2dc0a3ec113
child 538572 d03b95b35c350dca85269a9e8395292ed4b1fb3e
push id11522
push userffxbld-merge
push dateMon, 01 Jul 2019 09:00:55 +0000
treeherdermozilla-beta@53ea74d2bd09 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjya, cpearce
bugs1498742
milestone69.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 1498742 - Part 2 - Start the GMP sandbox earlier during process startup r=jya,cpearce Change the Mac GMP process launch to include sandboxing params on the command line to allow the sandbox to be started earlier during GMP process launch. Content, extension, and RDD processes have already been changed to start the sandbox earlier. Update GMPProcessParent to override GeckoChildProcessHost methods used to construct sandboxing parameters. Pass the plugin path as a sandbox parameter so that the sandbox rules can whitelist the plugin directory which is now read after the sandbox is enabled in the plugin process. On development builds, pass "testingReadPath" params so directories needed during automated tests can be whitelisted. Update Mac sandboxing code to detect GMP sandbox params on the command line and enable the sandbox with additional arguments needed for early sandbox start. Allow reverting to the old implementation by setting security.sandbox.gmp.mac.earlyinit to false. Differential Revision: https://phabricator.services.mozilla.com/D34085
browser/app/profile/firefox.js
dom/media/gmp/GMPChild.cpp
dom/media/gmp/GMPLoader.cpp
dom/media/gmp/GMPParent.cpp
dom/media/gmp/GMPProcessParent.cpp
dom/media/gmp/GMPProcessParent.h
dom/media/gmp/GMPService.cpp
dom/media/ipc/RDDProcessHost.cpp
dom/media/ipc/RDDProcessHost.h
ipc/glue/GeckoChildProcessHost.cpp
ipc/glue/GeckoChildProcessHost.h
security/sandbox/mac/Sandbox.h
security/sandbox/mac/Sandbox.mm
security/sandbox/mac/SandboxPolicyContent.h
security/sandbox/mac/SandboxPolicyGMP.h
xpcom/base/nsMacUtilsImpl.cpp
xpcom/base/nsMacUtilsImpl.h
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -1060,16 +1060,18 @@ pref("security.sandbox.gmp.win32k-disabl
 #endif
 
 #if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
 // Start the Mac sandbox early during child process startup instead
 // of when messaged by the parent after the message loop is running.
 pref("security.sandbox.content.mac.earlyinit", true);
 // Remove this pref once RDD early init is stable on Release.
 pref("security.sandbox.rdd.mac.earlyinit", true);
+// Remove this pref once GMP early init is stable on Release.
+pref("security.sandbox.gmp.mac.earlyinit", true);
 
 // This pref is discussed in bug 1083344, the naming is inspired from its
 // Windows counterpart, but on Mac it's an integer which means:
 // 0 -> "no sandbox" (nightly only)
 // 1 -> "preliminary content sandboxing enabled: write access to
 //       home directory is prevented"
 // 2 -> "preliminary content sandboxing enabled with profile protection:
 //       write access to home directory is prevented, read and write access
--- a/dom/media/gmp/GMPChild.cpp
+++ b/dom/media/gmp/GMPChild.cpp
@@ -12,16 +12,17 @@
 #include "GMPVideoHost.h"
 #include "nsDebugImpl.h"
 #include "nsExceptionHandler.h"
 #include "nsIFile.h"
 #include "nsXULAppAPI.h"
 #include "gmp-video-decode.h"
 #include "gmp-video-encode.h"
 #include "GMPPlatform.h"
+#include "GMPProcessParent.h"
 #include "mozilla/Algorithm.h"
 #include "mozilla/ipc/CrashReporterClient.h"
 #include "mozilla/ipc/ProcessChild.h"
 #include "mozilla/TextUtils.h"
 #include "GMPUtils.h"
 #include "prio.h"
 #include "base/task.h"
 #include "base/command_line.h"
@@ -555,26 +556,32 @@ mozilla::ipc::IPCResult GMPChild::Answer
   mGMPLoader = MakeUnique<GMPLoader>();
 #if defined(MOZ_SANDBOX)
   if (!mGMPLoader->CanSandbox()) {
     LOGD("%s Can't sandbox GMP, failing", __FUNCTION__);
     delete platformAPI;
     return IPC_FAIL(this, "Can't sandbox GMP.");
   }
 #endif
+
   bool isChromium = aAdapter.EqualsLiteral("chromium");
-#if defined(MOZ_SANDBOX) && defined(XP_MACOSX)
-  // Use of the chromium adapter indicates we are going to be
-  // running the Widevine plugin which requires access to the
-  // WindowServer in the Mac GMP sandbox policy.
-  if (!SetMacSandboxInfo(isChromium /* allow-window-server */)) {
-    NS_WARNING("Failed to set Mac GMP sandbox info");
-    delete platformAPI;
-    return IPC_FAIL(
-        this, nsPrintfCString("Failed to set Mac GMP sandbox info.").get());
+
+#if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
+  // If we started the sandbox at launch ("earlyinit"), then we don't
+  // need to setup sandbox arguments here with SetMacSandboxInfo().
+  if (!IsMacSandboxStarted()) {
+    // Use of the chromium adapter indicates we are going to be
+    // running the Widevine plugin which requires access to the
+    // WindowServer in the Mac GMP sandbox policy.
+    if (!SetMacSandboxInfo(isChromium /* allow-window-server */)) {
+      NS_WARNING("Failed to set Mac GMP sandbox info");
+      delete platformAPI;
+      return IPC_FAIL(
+          this, nsPrintfCString("Failed to set Mac GMP sandbox info.").get());
+    }
   }
 #endif
 
   GMPAdapter* adapter = nullptr;
   if (isChromium) {
     auto&& paths = MakeCDMHostVerificationPaths();
     GMP_LOG("%s CDM host paths=%s", __func__, ToCString(paths).get());
     adapter = new ChromiumCDMAdapter(std::move(paths));
--- a/dom/media/gmp/GMPLoader.cpp
+++ b/dom/media/gmp/GMPLoader.cpp
@@ -155,16 +155,22 @@ class WinSandboxStarter : public mozilla
   }
 };
 #endif
 
 #if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
 class MacSandboxStarter : public mozilla::gmp::SandboxStarter {
  public:
   bool Start(const char* aLibPath) override {
+    // If we started the sandbox at launch ("earlyinit"),
+    // then don't try to start the sandbox again.
+    if (IsMacSandboxStarted()) {
+      return true;
+    }
+
     std::string err;
     bool rv = mozilla::StartMacSandbox(mInfo, err);
     if (!rv) {
       fprintf(stderr, "sandbox_init() failed! Error \"%s\"\n", err.c_str());
     }
     return rv;
   }
   void SetSandboxInfo(MacSandboxInfo* aSandboxInfo) override {
--- a/dom/media/gmp/GMPParent.cpp
+++ b/dom/media/gmp/GMPParent.cpp
@@ -144,16 +144,19 @@ nsresult GMPParent::LoadProcess() {
   nsAutoString path;
   if (NS_WARN_IF(NS_FAILED(mDirectory->GetPath(path)))) {
     return NS_ERROR_FAILURE;
   }
   LOGD("%s: for %s", __FUNCTION__, NS_ConvertUTF16toUTF8(path).get());
 
   if (!mProcess) {
     mProcess = new GMPProcessParent(NS_ConvertUTF16toUTF8(path).get());
+#if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
+    mProcess->SetRequiresWindowServer(mAdapter.EqualsLiteral("chromium"));
+#endif
     if (!mProcess->Launch(30 * 1000)) {
       LOGD("%s: Failed to launch new child process", __FUNCTION__);
       mProcess->Delete();
       mProcess = nullptr;
       return NS_ERROR_FAILURE;
     }
 
     mChildPid = base::GetProcId(mProcess->GetChildProcessHandle());
--- a/dom/media/gmp/GMPProcessParent.cpp
+++ b/dom/media/gmp/GMPProcessParent.cpp
@@ -13,30 +13,75 @@
 #endif
 #include "GMPLog.h"
 
 #include "base/string_util.h"
 #include "base/process_util.h"
 
 #include <string>
 
+#if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
+#  include "mozilla/dom/ContentChild.h"
+#  include "mozilla/Sandbox.h"
+#  include "mozilla/SandboxSettings.h"
+#  include "nsMacUtilsImpl.h"
+#endif
+
 using std::string;
 using std::vector;
 
 using mozilla::gmp::GMPProcessParent;
 using mozilla::ipc::GeckoChildProcessHost;
 
 static const int kInvalidFd = -1;
 
 namespace mozilla {
 namespace gmp {
 
+#if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
+bool GMPProcessParent::sLaunchWithMacSandbox = true;
+bool GMPProcessParent::sMacSandboxGMPLogging = false;
+#  if defined(DEBUG)
+bool GMPProcessParent::sIsMainThreadInitDone = false;
+#  endif
+#endif
+
+#if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
+/* static */
+void GMPProcessParent::InitStaticMainThread() {
+  // The GMPProcessParent constructor is called off the
+  // main thread. Do main thread initialization here.
+  MOZ_ASSERT(NS_IsMainThread());
+  sLaunchWithMacSandbox =
+      Preferences::GetBool("security.sandbox.gmp.mac.earlyinit", true) &&
+      (getenv("MOZ_DISABLE_GMP_SANDBOX") == nullptr);
+  sMacSandboxGMPLogging =
+      Preferences::GetBool("security.sandbox.logging.enabled") ||
+      PR_GetEnv("MOZ_SANDBOX_GMP_LOGGING") || PR_GetEnv("MOZ_SANDBOX_LOGGING");
+  GMP_LOG("GMPProcessParent::InitStaticMainThread: earlyinit=%s, logging=%s",
+          sLaunchWithMacSandbox ? "true" : "false",
+          sMacSandboxGMPLogging ? "true" : "false");
+#  if defined(DEBUG)
+  sIsMainThreadInitDone = true;
+#  endif
+}
+#endif
+
 GMPProcessParent::GMPProcessParent(const std::string& aGMPPath)
-    : GeckoChildProcessHost(GeckoProcessType_GMPlugin), mGMPPath(aGMPPath) {
+    : GeckoChildProcessHost(GeckoProcessType_GMPlugin),
+      mGMPPath(aGMPPath)
+#if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
+      ,
+      mRequiresWindowServer(false)
+#endif
+{
   MOZ_COUNT_CTOR(GMPProcessParent);
+#if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
+  MOZ_ASSERT(sIsMainThreadInitDone == true);
+#endif
 }
 
 GMPProcessParent::~GMPProcessParent() { MOZ_COUNT_DTOR(GMPProcessParent); }
 
 bool GMPProcessParent::Launch(int32_t aTimeoutMs) {
   vector<string> args;
 
 #if defined(XP_WIN) && defined(MOZ_SANDBOX)
@@ -63,16 +108,31 @@ bool GMPProcessParent::Launch(int32_t aT
     std::wstring sandboxGMPPath(wGMPPath);
     sandboxGMPPath.insert(1, L"??\\UNC");
     mAllowedFilesRead.push_back(sandboxGMPPath + L"\\*");
   } else {
     mAllowedFilesRead.push_back(wGMPPath + L"\\*");
   }
 
   args.push_back(WideToUTF8(wGMPPath));
+#elif defined(XP_MACOSX) && defined(MOZ_SANDBOX)
+  // Resolve symlinks in the plugin path. The sandbox prevents
+  // resolving symlinks in the child process if access to link
+  // source file is denied.
+  nsAutoCString normalizedPath;
+  nsresult rv = NormalizePath(mGMPPath.c_str(), normalizedPath);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    GMP_LOG(
+        "GMPProcessParent::Launch: "
+        "plugin path normaliziation failed for path: %s",
+        mGMPPath.c_str());
+    args.push_back(mGMPPath);
+  } else {
+    args.push_back(normalizedPath.get());
+  }
 #else
   args.push_back(mGMPPath);
 #endif
 
 #ifdef MOZ_WIDGET_ANDROID
   // Add dummy values for pref and pref map to the file descriptors remapping
   // table. See bug 1440207 and 1481139.
   AddFdToRemap(kInvalidFd, kInvalidFd);
@@ -93,10 +153,113 @@ void GMPProcessParent::DoDelete() {
 
   if (mDeletedCallback) {
     mDeletedCallback->Run();
   }
 
   Destroy();
 }
 
+#if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
+bool GMPProcessParent::IsMacSandboxLaunchEnabled() {
+  return sLaunchWithMacSandbox;
+}
+
+void GMPProcessParent::SetRequiresWindowServer(bool aRequiresWindowServer) {
+  mRequiresWindowServer = aRequiresWindowServer;
+}
+
+bool GMPProcessParent::FillMacSandboxInfo(MacSandboxInfo& aInfo) {
+  aInfo.type = MacSandboxType_GMP;
+  aInfo.hasWindowServer = mRequiresWindowServer;
+  aInfo.shouldLog = (aInfo.shouldLog || sMacSandboxGMPLogging);
+  nsAutoCString appPath;
+  if (!nsMacUtilsImpl::GetAppPath(appPath)) {
+    GMP_LOG("GMPProcessParent::FillMacSandboxInfo: failed to get app path");
+    return false;
+  }
+  aInfo.appPath.assign(appPath.get());
+
+  GMP_LOG(
+      "GMPProcessParent::FillMacSandboxInfo: "
+      "plugin dir path: %s",
+      mGMPPath.c_str());
+  nsCOMPtr<nsIFile> pluginDir;
+  nsresult rv = NS_NewLocalFile(NS_ConvertUTF8toUTF16(mGMPPath.c_str()), true,
+                                getter_AddRefs(pluginDir));
+  if (NS_FAILED(rv)) {
+    GMP_LOG(
+        "GMPProcessParent::FillMacSandboxInfo: "
+        "NS_NewLocalFile failed for plugin dir, rv=%d",
+        rv);
+    return false;
+  }
+
+  rv = pluginDir->Normalize();
+  if (NS_FAILED(rv)) {
+    GMP_LOG(
+        "GMPProcessParent::FillMacSandboxInfo: "
+        "failed to normalize plugin dir path, rv=%d",
+        rv);
+    return false;
+  }
+
+  nsAutoCString resolvedPluginPath;
+  pluginDir->GetNativePath(resolvedPluginPath);
+  aInfo.pluginPath.assign(resolvedPluginPath.get());
+  GMP_LOG(
+      "GMPProcessParent::FillMacSandboxInfo: "
+      "resolved plugin dir path: %s",
+      resolvedPluginPath.get());
+
+  if (mozilla::IsDevelopmentBuild()) {
+    GMP_LOG("GMPProcessParent::FillMacSandboxInfo: IsDevelopmentBuild()=true");
+
+    // Repo dir
+    nsCOMPtr<nsIFile> repoDir;
+    rv = nsMacUtilsImpl::GetRepoDir(getter_AddRefs(repoDir));
+    if (NS_FAILED(rv)) {
+      GMP_LOG("GMPProcessParent::FillMacSandboxInfo: failed to get repo dir");
+      return false;
+    }
+    nsCString repoDirPath;
+    Unused << repoDir->GetNativePath(repoDirPath);
+    aInfo.testingReadPath1 = repoDirPath.get();
+    GMP_LOG(
+        "GMPProcessParent::FillMacSandboxInfo: "
+        "repo dir path: %s",
+        repoDirPath.get());
+
+    // Object dir
+    nsCOMPtr<nsIFile> objDir;
+    rv = nsMacUtilsImpl::GetObjDir(getter_AddRefs(objDir));
+    if (NS_FAILED(rv)) {
+      GMP_LOG("GMPProcessParent::FillMacSandboxInfo: failed to get object dir");
+      return false;
+    }
+    nsCString objDirPath;
+    Unused << objDir->GetNativePath(objDirPath);
+    aInfo.testingReadPath2 = objDirPath.get();
+    GMP_LOG(
+        "GMPProcessParent::FillMacSandboxInfo: "
+        "object dir path: %s",
+        objDirPath.get());
+  }
+  return true;
+}
+
+nsresult GMPProcessParent::NormalizePath(const char* aPath,
+                                         nsACString& aNormalizedPath) {
+  nsCOMPtr<nsIFile> fileOrDir;
+  nsresult rv = NS_NewLocalFile(NS_ConvertUTF8toUTF16(aPath), true,
+                                getter_AddRefs(fileOrDir));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  rv = fileOrDir->Normalize();
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  fileOrDir->GetNativePath(aNormalizedPath);
+  return NS_OK;
+}
+#endif
+
 }  // namespace gmp
 }  // namespace mozilla
--- a/dom/media/gmp/GMPProcessParent.h
+++ b/dom/media/gmp/GMPProcessParent.h
@@ -27,26 +27,78 @@ class GMPProcessParent final : public mo
   // after timeoutMs, this method will return false.
   bool Launch(int32_t aTimeoutMs);
 
   void Delete(nsCOMPtr<nsIRunnable> aCallback = nullptr);
 
   bool CanShutdown() override { return true; }
   const std::string& GetPluginFilePath() { return mGMPPath; }
 
+#if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
+  // Init static members on the main thread
+  static void InitStaticMainThread();
+
+  // Read prefs and environment variables to determine
+  // when and if to start the Mac sandbox for the child
+  // process. Starting the sandbox at launch is the new
+  // preferred method. Code to support starting the sandbox
+  // later at plugin start time should be removed once
+  // starting at launch is stable and shipping.
+  bool IsMacSandboxLaunchEnabled() override;
+
+  // For process sandboxing purposes, set whether or not this
+  // instance of the GMP process requires access to the macOS
+  // window server. At present, Widevine requires window server
+  // access, but OpenH264 decoding does not.
+  void SetRequiresWindowServer(bool aRequiresWindowServer);
+
+  // Return the sandbox type to be used with this process type.
+  static MacSandboxType GetMacSandboxType() { return MacSandboxType_GMP; };
+#endif
+
   using mozilla::ipc::GeckoChildProcessHost::GetChannel;
   using mozilla::ipc::GeckoChildProcessHost::GetChildProcessHandle;
 
  private:
   ~GMPProcessParent();
 
   void DoDelete();
 
   std::string mGMPPath;
   nsCOMPtr<nsIRunnable> mDeletedCallback;
 
+#if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
+  // Indicates whether we'll start the Mac GMP sandbox during
+  // process launch (earlyinit) which is the new preferred method
+  // or later in the process lifetime.
+  static bool sLaunchWithMacSandbox;
+
+  // Whether or not Mac sandbox violation logging is enabled.
+  static bool sMacSandboxGMPLogging;
+
+  // Override so we can set GMP-specific sandbox parameters
+  bool FillMacSandboxInfo(MacSandboxInfo& aInfo) override;
+
+  // For normalizing paths to be compatible with sandboxing.
+  // We use normalized paths to generate the sandbox ruleset. Once
+  // the sandbox has been started, resolving symlinks that point to
+  // allowed directories could require reading paths not allowed by
+  // the sandbox, so we should only attempt to load plugin libraries
+  // using normalized paths.
+  static nsresult NormalizePath(const char* aPath, nsACString& aNormalizedPath);
+
+  // Controls whether or not the sandbox will be configured with
+  // window service access.
+  bool mRequiresWindowServer;
+
+#  if defined(DEBUG)
+  // Used to assert InitStaticMainThread() is called before the constructor.
+  static bool sIsMainThreadInitDone;
+#  endif
+#endif
+
   DISALLOW_COPY_AND_ASSIGN(GMPProcessParent);
 };
 
 }  // namespace gmp
 }  // namespace mozilla
 
 #endif  // ifndef GMPProcessParent_h
--- a/dom/media/gmp/GMPService.cpp
+++ b/dom/media/gmp/GMPService.cpp
@@ -8,16 +8,17 @@
 #include "GMPServiceChild.h"
 #include "GMPContentParent.h"
 #include "prio.h"
 #include "mozilla/Logging.h"
 #include "GMPParent.h"
 #include "GMPVideoDecoderParent.h"
 #include "nsIObserverService.h"
 #include "GeckoChildProcessHost.h"
+#include "GMPProcessParent.h"
 #include "mozilla/ClearOnShutdown.h"
 #include "mozilla/SyncRunnable.h"
 #include "nsXPCOMPrivate.h"
 #include "mozilla/Services.h"
 #include "nsNativeCharsetUtils.h"
 #include "nsIXULAppInfo.h"
 #include "nsIConsoleService.h"
 #include "mozilla/Unused.h"
@@ -97,23 +98,27 @@ class GMPServiceCreateHelper final : pub
     MOZ_ASSERT(NS_IsMainThread());
 
     if (!sSingletonService) {
       if (XRE_IsParentProcess()) {
         RefPtr<GeckoMediaPluginServiceParent> service =
             new GeckoMediaPluginServiceParent();
         service->Init();
         sSingletonService = service;
+#if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
+        // GMPProcessParent should only be instantiated in the parent
+        // so initialization only needs to be done in the parent.
+        GMPProcessParent::InitStaticMainThread();
+#endif
       } else {
         RefPtr<GeckoMediaPluginServiceChild> service =
             new GeckoMediaPluginServiceChild();
         service->Init();
         sSingletonService = service;
       }
-
       ClearOnShutdown(&sSingletonService);
     }
 
     RefPtr<GeckoMediaPluginService> service = sSingletonService.get();
     return service.forget();
   }
 
   NS_IMETHOD
--- a/dom/media/ipc/RDDProcessHost.cpp
+++ b/dom/media/ipc/RDDProcessHost.cpp
@@ -256,25 +256,26 @@ void RDDProcessHost::DestroyProcess() {
   }
 
   MessageLoop::current()->PostTask(
       NS_NewRunnableFunction("DestroyProcessRunnable", [this] { Destroy(); }));
 }
 
 #if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
 /* static */
-void RDDProcessHost::StaticFillMacSandboxInfo(MacSandboxInfo& aInfo) {
+bool RDDProcessHost::StaticFillMacSandboxInfo(MacSandboxInfo& aInfo) {
   GeckoChildProcessHost::StaticFillMacSandboxInfo(aInfo);
   if (!aInfo.shouldLog && PR_GetEnv("MOZ_SANDBOX_RDD_LOGGING")) {
     aInfo.shouldLog = true;
   }
+  return true;
 }
 
-void RDDProcessHost::FillMacSandboxInfo(MacSandboxInfo& aInfo) {
-  RDDProcessHost::StaticFillMacSandboxInfo(aInfo);
+bool RDDProcessHost::FillMacSandboxInfo(MacSandboxInfo& aInfo) {
+  return RDDProcessHost::StaticFillMacSandboxInfo(aInfo);
 }
 
 /* static */
 MacSandboxType RDDProcessHost::GetMacSandboxType() {
   return GeckoChildProcessHost::GetDefaultMacSandboxType();
 }
 #endif
 
--- a/dom/media/ipc/RDDProcessHost.h
+++ b/dom/media/ipc/RDDProcessHost.h
@@ -94,17 +94,17 @@ class RDDProcessHost final : public mozi
 
   // Used for tests and diagnostics
   void KillProcess();
 
 #if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
   // To allow filling a MacSandboxInfo from the child
   // process without an instance of RDDProcessHost.
   // Only needed for late-start sandbox enabling.
-  static void StaticFillMacSandboxInfo(MacSandboxInfo& aInfo);
+  static bool StaticFillMacSandboxInfo(MacSandboxInfo& aInfo);
 
   // Return the sandbox type to be used with this process type.
   static MacSandboxType GetMacSandboxType();
 #endif
 
  private:
   ~RDDProcessHost();
 
@@ -125,17 +125,17 @@ class RDDProcessHost final : public mozi
 
 #if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
   static bool sLaunchWithMacSandbox;
 
   // Sandbox the RDD process at launch for all instances
   bool IsMacSandboxLaunchEnabled() override { return sLaunchWithMacSandbox; }
 
   // Override so we can turn on RDD process-specific sandbox logging
-  void FillMacSandboxInfo(MacSandboxInfo& aInfo) override;
+  bool FillMacSandboxInfo(MacSandboxInfo& aInfo) override;
 #endif
 
   DISALLOW_COPY_AND_ASSIGN(RDDProcessHost);
 
   Listener* mListener;
   mozilla::ipc::TaskFactory<RDDProcessHost> mTaskFactory;
 
   enum class LaunchPhase { Unlaunched, Waiting, Complete };
--- a/ipc/glue/GeckoChildProcessHost.cpp
+++ b/ipc/glue/GeckoChildProcessHost.cpp
@@ -63,16 +63,17 @@
 #  endif
 #endif
 
 #if defined(XP_LINUX) && defined(MOZ_SANDBOX)
 #  include "mozilla/SandboxLaunch.h"
 #endif
 
 #if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
+#  include "GMPProcessParent.h"
 #  include "nsMacUtilsImpl.h"
 #endif
 
 #include "nsTArray.h"
 #include "nsClassHashtable.h"
 #include "nsHashKeys.h"
 #include "nsNativeCharsetUtils.h"
 #include "nscore.h"  // for NS_FREE_PERMANENT_DATA
@@ -365,18 +366,18 @@ bool GeckoChildProcessHost::SyncLaunch(s
   }
   return WaitUntilConnected(aTimeoutMs);
 }
 
 bool GeckoChildProcessHost::AsyncLaunch(std::vector<std::string> aExtraOpts) {
   PrepareLaunch();
 
 #if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
-  if (IsMacSandboxLaunchEnabled()) {
-    AppendMacSandboxParams(aExtraOpts);
+  if (IsMacSandboxLaunchEnabled() && !AppendMacSandboxParams(aExtraOpts)) {
+    return false;
   }
 #endif
 
   MessageLoop* ioLoop = XRE_GetIOMessageLoop();
 
   MOZ_ASSERT(mHandlePromise == nullptr);
   mHandlePromise = new HandlePromise::Private(__func__);
 
@@ -1392,62 +1393,69 @@ void GeckoChildProcessHost::LaunchAndroi
 
   if (process_handle) {
     *process_handle = handle;
   }
 }
 #endif
 
 #if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
-void GeckoChildProcessHost::AppendMacSandboxParams(StringVector& aArgs) {
+bool GeckoChildProcessHost::AppendMacSandboxParams(StringVector& aArgs) {
   MacSandboxInfo info;
-  FillMacSandboxInfo(info);
+  if (!FillMacSandboxInfo(info)) {
+    return false;
+  }
   info.AppendAsParams(aArgs);
+  return true;
 }
 
 // Fill |aInfo| with the flags needed to launch the utility sandbox
 /* static */
-void GeckoChildProcessHost::StaticFillMacSandboxInfo(MacSandboxInfo& aInfo) {
+bool GeckoChildProcessHost::StaticFillMacSandboxInfo(MacSandboxInfo& aInfo) {
   aInfo.type = GetDefaultMacSandboxType();
   aInfo.shouldLog = Preferences::GetBool("security.sandbox.logging.enabled") ||
                     PR_GetEnv("MOZ_SANDBOX_LOGGING");
 
   nsAutoCString appPath;
   if (!nsMacUtilsImpl::GetAppPath(appPath)) {
     MOZ_CRASH("Failed to get app path");
   }
   aInfo.appPath.assign(appPath.get());
+  return true;
 }
 
-void GeckoChildProcessHost::FillMacSandboxInfo(MacSandboxInfo& aInfo) {
-  GeckoChildProcessHost::StaticFillMacSandboxInfo(aInfo);
+bool GeckoChildProcessHost::FillMacSandboxInfo(MacSandboxInfo& aInfo) {
+  return GeckoChildProcessHost::StaticFillMacSandboxInfo(aInfo);
 }
 
 //
 // If early sandbox startup is enabled for this process type, map the
 // process type to the sandbox type and enable the sandbox. Returns true
 // if no errors were encountered or if early sandbox startup is not
 // enabled for this process. Returns false if an error was encountered.
 //
 /* static */
 bool GeckoChildProcessHost::StartMacSandbox(int aArgc, char** aArgv,
                                             std::string& aErrorMessage) {
   MacSandboxType sandboxType = MacSandboxType_Invalid;
   switch (XRE_GetProcessType()) {
-    // For now, only support early sandbox startup for content
-    // processes. Add case statements for the additional process
-    // types once early sandbox startup is implemented for them.
+    // For now, only support early sandbox startup for content,
+    // RDD, and GMP processes. Add case statements for the additional
+    // process types once early sandbox startup is implemented for them.
     case GeckoProcessType_Content:
       // Content processes don't use GeckoChildProcessHost
       // to configure sandboxing so hard code the sandbox type.
       sandboxType = MacSandboxType_Content;
       break;
     case GeckoProcessType_RDD:
       sandboxType = RDDProcessHost::GetMacSandboxType();
       break;
+    case GeckoProcessType_GMPlugin:
+      sandboxType = gmp::GMPProcessParent::GetMacSandboxType();
+      break;
     default:
       return true;
   }
   return mozilla::StartMacSandboxIfEnabled(sandboxType, aArgc, aArgv,
                                            aErrorMessage);
 }
 
 #endif /* XP_MACOSX && MOZ_SANDBOX */
--- a/ipc/glue/GeckoChildProcessHost.h
+++ b/ipc/glue/GeckoChildProcessHost.h
@@ -135,17 +135,17 @@ class GeckoChildProcessHost : public Chi
 
   // For bug 943174: Skip the EnsureProcessTerminated call in the destructor.
   void SetAlreadyDead();
 
 #if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
   // To allow filling a MacSandboxInfo from the child
   // process without an instance of RDDProcessHost.
   // Only needed for late-start sandbox enabling.
-  static void StaticFillMacSandboxInfo(MacSandboxInfo& aInfo);
+  static bool StaticFillMacSandboxInfo(MacSandboxInfo& aInfo);
 
   // Start the sandbox from the child process.
   static bool StartMacSandbox(int aArgc, char** aArgv,
                               std::string& aErrorMessage);
 
   // The sandbox type that will be use when sandboxing is
   // enabled in the derived class and FillMacSandboxInfo
   // has not been overridden.
@@ -210,22 +210,22 @@ class GeckoChildProcessHost : public Chi
 
 #if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
   // Override this method to return true to launch the child process
   // using the Mac utility (by default) sandbox. Override
   // FillMacSandboxInfo() to change the sandbox type and settings.
   virtual bool IsMacSandboxLaunchEnabled() { return false; }
 
   // Fill a MacSandboxInfo to configure the sandbox
-  virtual void FillMacSandboxInfo(MacSandboxInfo& aInfo);
+  virtual bool FillMacSandboxInfo(MacSandboxInfo& aInfo);
 
   // Adds the command line arguments needed to enable
   // sandboxing of the child process at startup before
   // the child event loop is up.
-  virtual void AppendMacSandboxParams(StringVector& aArgs);
+  virtual bool AppendMacSandboxParams(StringVector& aArgs);
 #endif
 
  private:
   DISALLOW_EVIL_CONSTRUCTORS(GeckoChildProcessHost);
 
   // Does the actual work for AsyncLaunch; run in a thread pool
   // (or, on Windows, a dedicated thread).
   bool PerformAsyncLaunch(StringVector aExtraOpts);
--- a/security/sandbox/mac/Sandbox.h
+++ b/security/sandbox/mac/Sandbox.h
@@ -31,16 +31,17 @@ typedef struct _MacSandboxInfo {
   void AppendAsParams(std::vector<std::string>& aParams) const;
   static void AppendFileAccessParam(std::vector<std::string>& aParams,
                                     bool aHasFilePrivileges);
 
  private:
   void AppendStartupParam(std::vector<std::string>& aParams) const;
   void AppendLoggingParam(std::vector<std::string>& aParams) const;
   void AppendAppPathParam(std::vector<std::string>& aParams) const;
+  void AppendPluginPathParam(std::vector<std::string>& aParams) const;
   void AppendLevelParam(std::vector<std::string>& aParams) const;
   void AppendAudioParam(std::vector<std::string>& aParams) const;
   void AppendWindowServerParam(std::vector<std::string>& aParams) const;
   void AppendReadPathParams(std::vector<std::string>& aParams) const;
 #ifdef DEBUG
   void AppendDebugWriteDirParam(std::vector<std::string>& aParams) const;
 #endif
 
@@ -71,15 +72,16 @@ typedef struct _MacSandboxInfo {
   bool shouldLog;
 } MacSandboxInfo;
 
 namespace mozilla {
 
 bool StartMacSandbox(MacSandboxInfo const& aInfo, std::string& aErrorMessage);
 bool StartMacSandboxIfEnabled(MacSandboxType aSandboxType, int aArgc,
                               char** aArgv, std::string& aErrorMessage);
+bool IsMacSandboxStarted();
 #ifdef DEBUG
 void AssertMacSandboxEnabled();
 #endif /* DEBUG */
 
 }  // namespace mozilla
 
 #endif  // mozilla_Sandbox_h
--- a/security/sandbox/mac/Sandbox.mm
+++ b/security/sandbox/mac/Sandbox.mm
@@ -28,19 +28,17 @@
 // some/all of the Macs in Mozilla's build system. Further,
 // sandbox_init_with_parameters is not included in the header.  For the time
 // being (until this problem is resolved), we refer directly to what we need
 // from it, rather than including it here.
 extern "C" int sandbox_init(const char* profile, uint64_t flags, char** errorbuf);
 extern "C" int sandbox_init_with_parameters(const char* profile, uint64_t flags,
                                             const char* const parameters[], char** errorbuf);
 extern "C" void sandbox_free_error(char* errorbuf);
-#ifdef DEBUG
 extern "C" int sandbox_check(pid_t pid, const char* operation, int type, ...);
-#endif
 
 #define MAC_OS_X_VERSION_10_0_HEX 0x00001000
 #define MAC_OS_X_VERSION_10_6_HEX 0x00001060
 #define MAC_OS_X_VERSION_10_7_HEX 0x00001070
 #define MAC_OS_X_VERSION_10_8_HEX 0x00001080
 #define MAC_OS_X_VERSION_10_9_HEX 0x00001090
 #define MAC_OS_X_VERSION_10_10_HEX 0x000010A0
 
@@ -146,16 +144,21 @@ void MacSandboxInfo::AppendAsParams(std:
       this->AppendWindowServerParam(aParams);
       this->AppendReadPathParams(aParams);
 #ifdef DEBUG
       this->AppendDebugWriteDirParam(aParams);
 #endif
       break;
     case MacSandboxType_Utility:
       break;
+    case MacSandboxType_GMP:
+      this->AppendPluginPathParam(aParams);
+      this->AppendWindowServerParam(aParams);
+      this->AppendReadPathParams(aParams);
+      break;
     default:
       // Before supporting a new process type, add a case statement
       // here to append any neccesary process-type-specific params.
       MOZ_RELEASE_ASSERT(false);
       break;
   }
 }
 
@@ -169,16 +172,21 @@ void MacSandboxInfo::AppendLoggingParam(
   }
 }
 
 void MacSandboxInfo::AppendAppPathParam(std::vector<std::string>& aParams) const {
   aParams.push_back("-sbAppPath");
   aParams.push_back(this->appPath);
 }
 
+void MacSandboxInfo::AppendPluginPathParam(std::vector<std::string>& aParams) const {
+  aParams.push_back("-sbPluginPath");
+  aParams.push_back(this->pluginPath);
+}
+
 /* static */
 void MacSandboxInfo::AppendFileAccessParam(std::vector<std::string>& aParams,
                                            bool aHasFilePrivileges) {
   if (aHasFilePrivileges) {
     aParams.push_back("-sbAllowFileAccess");
   }
 }
 
@@ -293,24 +301,38 @@ bool StartMacSandbox(MacSandboxInfo cons
     if (!aInfo.crashServerPort.empty()) {
       params.push_back("CRASH_PORT");
       params.push_back(aInfo.crashServerPort.c_str());
     }
   } else if (aInfo.type == MacSandboxType_GMP) {
     profile = const_cast<char*>(SandboxPolicyGMP);
     params.push_back("SHOULD_LOG");
     params.push_back(aInfo.shouldLog ? "TRUE" : "FALSE");
-    params.push_back("PLUGIN_BINARY_PATH");
-    params.push_back(aInfo.pluginBinaryPath.c_str());
     params.push_back("APP_PATH");
     params.push_back(aInfo.appPath.c_str());
-    params.push_back("APP_BINARY_PATH");
-    params.push_back(aInfo.appBinaryPath.c_str());
+    params.push_back("PLUGIN_PATH");
+    params.push_back(aInfo.pluginPath.c_str());
+    if (!aInfo.pluginBinaryPath.empty()) {
+      params.push_back("PLUGIN_BINARY_PATH");
+      params.push_back(aInfo.pluginBinaryPath.c_str());
+    }
     params.push_back("HAS_WINDOW_SERVER");
     params.push_back(aInfo.hasWindowServer ? "TRUE" : "FALSE");
+    if (!aInfo.crashServerPort.empty()) {
+      params.push_back("CRASH_PORT");
+      params.push_back(aInfo.crashServerPort.c_str());
+    }
+    if (!aInfo.testingReadPath1.empty()) {
+      params.push_back("TESTING_READ_PATH1");
+      params.push_back(aInfo.testingReadPath1.c_str());
+    }
+    if (!aInfo.testingReadPath2.empty()) {
+      params.push_back("TESTING_READ_PATH2");
+      params.push_back(aInfo.testingReadPath2.c_str());
+    }
   } else if (aInfo.type == MacSandboxType_Content) {
     MOZ_ASSERT(aInfo.level >= 1);
     if (aInfo.level >= 1) {
       profile = SandboxPolicyContent;
       params.push_back("SHOULD_LOG");
       params.push_back(aInfo.shouldLog ? "TRUE" : "FALSE");
       params.push_back("SANDBOX_LEVEL_1");
       params.push_back(aInfo.level == 1 ? "TRUE" : "FALSE");
@@ -428,17 +450,17 @@ bool GetContentSandboxParamsFromArgs(int
   // Ensure we find these paramaters in the command
   // line arguments. Return false if any are missing.
   bool foundSandboxLevel = false;
   bool foundValidSandboxLevel = false;
   bool foundAppPath = false;
 
   // Read access directories used in testing
   int nTestingReadPaths = 0;
-  std::string testingReadPaths[MAX_TESTING_READ_PATHS] = {};
+  std::string testingReadPaths[MAX_CONTENT_TESTING_READ_PATHS] = {};
 
   // Collect sandbox params from CLI arguments
   for (int i = 0; i < aArgc; i++) {
     if ((strcmp(aArgv[i], "-sbLevel") == 0) && (i + 1 < aArgc)) {
       std::stringstream ss(aArgv[i + 1]);
       int level = 0;
       ss >> level;
       foundSandboxLevel = true;
@@ -474,17 +496,19 @@ bool GetContentSandboxParamsFromArgs(int
     if ((strcmp(aArgv[i], "-sbAppPath") == 0) && (i + 1 < aArgc)) {
       foundAppPath = true;
       aInfo.appPath.assign(aArgv[i + 1]);
       i++;
       continue;
     }
 
     if ((strcmp(aArgv[i], "-sbTestingReadPath") == 0) && (i + 1 < aArgc)) {
-      MOZ_ASSERT(nTestingReadPaths < MAX_TESTING_READ_PATHS);
+      if (nTestingReadPaths >= MAX_CONTENT_TESTING_READ_PATHS) {
+        MOZ_CRASH("Too many content process -sbTestingReadPath arguments");
+      }
       testingReadPaths[nTestingReadPaths] = aArgv[i + 1];
       nTestingReadPaths++;
       i++;
       continue;
     }
 
     if ((strcmp(aArgv[i], "-profile") == 0) && (i + 1 < aArgc)) {
       aInfo.hasSandboxedProfile = true;
@@ -566,16 +590,87 @@ bool GetUtilitySandboxParamsFromArgs(int
     fprintf(stderr, "Utility sandbox disabled due to "
                     "missing sandbox CLI app path parameter.\n");
     return false;
   }
 
   return true;
 }
 
+bool GetPluginSandboxParamsFromArgs(int aArgc, char** aArgv, MacSandboxInfo& aInfo) {
+  // Ensure we find these paramaters in the command
+  // line arguments. Return false if any are missing.
+  bool foundAppPath = false;
+  bool foundPluginPath = false;
+
+  // Read access directories used in testing
+  int nTestingReadPaths = 0;
+  std::string testingReadPaths[MAX_GMP_TESTING_READ_PATHS] = {};
+
+  // Collect sandbox params from CLI arguments
+  for (int i = 0; i < aArgc; i++) {
+    if (strcmp(aArgv[i], "-sbLogging") == 0) {
+      aInfo.shouldLog = true;
+      continue;
+    }
+
+    if ((strcmp(aArgv[i], "-sbAppPath") == 0) && (i + 1 < aArgc)) {
+      foundAppPath = true;
+      aInfo.appPath.assign(aArgv[i + 1]);
+      i++;
+      continue;
+    }
+
+    if ((strcmp(aArgv[i], "-sbPluginPath") == 0) && (i + 1 < aArgc)) {
+      foundPluginPath = true;
+      aInfo.pluginPath.assign(aArgv[i + 1]);
+      i++;
+      continue;
+    }
+
+    if (strcmp(aArgv[i], "-sbAllowWindowServer") == 0) {
+      aInfo.hasWindowServer = true;
+      continue;
+    }
+
+    if ((strcmp(aArgv[i], "-sbTestingReadPath") == 0) && (i + 1 < aArgc)) {
+      if (nTestingReadPaths >= MAX_GMP_TESTING_READ_PATHS) {
+        MOZ_CRASH("Too many GMP process -sbTestingReadPath arguments");
+      }
+      testingReadPaths[nTestingReadPaths] = aArgv[i + 1];
+      nTestingReadPaths++;
+      i++;
+      continue;
+    }
+
+    // Handle crash server positional argument
+    if (strstr(aArgv[i], "gecko-crash-server-pipe") != NULL) {
+      aInfo.crashServerPort.assign(aArgv[i]);
+      continue;
+    }
+  }
+
+  if (!foundPluginPath) {
+    fprintf(stderr, "GMP sandbox disabled due to "
+                    "missing sandbox CLI plugin path parameter.\n");
+    return false;
+  }
+
+  if (!foundAppPath) {
+    fprintf(stderr, "GMP sandbox disabled due to "
+                    "missing sandbox CLI app path parameter.\n");
+    return false;
+  }
+
+  aInfo.testingReadPath1 = testingReadPaths[0];
+  aInfo.testingReadPath2 = testingReadPaths[1];
+
+  return true;
+}
+
 /*
  * Returns true if no errors were encountered or if early sandbox startup is
  * not enabled for this process. Returns false if an error was encountered.
  */
 bool StartMacSandboxIfEnabled(const MacSandboxType aSandboxType, int aArgc, char** aArgv,
                               std::string& aErrorMessage) {
   bool earlyStartupEnabled = false;
 
@@ -606,22 +701,29 @@ bool StartMacSandboxIfEnabled(const MacS
         return false;
       }
       break;
     case MacSandboxType_Utility:
       if (!GetUtilitySandboxParamsFromArgs(aArgc, aArgv, info)) {
         return false;
       }
       break;
+    case MacSandboxType_GMP:
+      if (!GetPluginSandboxParamsFromArgs(aArgc, aArgv, info)) {
+        return false;
+      }
+      break;
     default:
       MOZ_RELEASE_ASSERT(false);
       break;
   }
 
   return StartMacSandbox(info, aErrorMessage);
 }
 
+bool IsMacSandboxStarted() { return sandbox_check(getpid(), NULL, 0) == 1; }
+
 #ifdef DEBUG
 // sandbox_check returns 1 if the specified process is sandboxed
 void AssertMacSandboxEnabled() { MOZ_ASSERT(sandbox_check(getpid(), NULL, 0) == 1); }
 #endif /* DEBUG */
 
 }  // namespace mozilla
--- a/security/sandbox/mac/SandboxPolicyContent.h
+++ b/security/sandbox/mac/SandboxPolicyContent.h
@@ -1,17 +1,17 @@
 /* -*- 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 mozilla_SandboxPolicyContent_h
 #define mozilla_SandboxPolicyContent_h
 
-#define MAX_TESTING_READ_PATHS 4
+#define MAX_CONTENT_TESTING_READ_PATHS 4
 
 namespace mozilla {
 
 static const char SandboxPolicyContent[] = R"SANDBOX_LITERAL(
   (version 1)
 
   (define should-log (param "SHOULD_LOG"))
   (define sandbox-level-1 (param "SANDBOX_LEVEL_1"))
--- a/security/sandbox/mac/SandboxPolicyGMP.h
+++ b/security/sandbox/mac/SandboxPolicyGMP.h
@@ -1,26 +1,31 @@
 /* -*- 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 mozilla_SandboxPolicyGMP_h
 #define mozilla_SandboxPolicyGMP_h
 
+#define MAX_GMP_TESTING_READ_PATHS 2
+
 namespace mozilla {
 
 static const char SandboxPolicyGMP[] = R"SANDBOX_LITERAL(
   (version 1)
 
   (define should-log (param "SHOULD_LOG"))
+  (define app-path (param "APP_PATH"))
+  (define plugin-path (param "PLUGIN_PATH"))
   (define plugin-binary-path (param "PLUGIN_BINARY_PATH"))
-  (define app-path (param "APP_PATH"))
-  (define app-binary-path (param "APP_BINARY_PATH"))
+  (define crashPort (param "CRASH_PORT"))
   (define hasWindowServer (param "HAS_WINDOW_SERVER"))
+  (define testingReadPath1 (param "TESTING_READ_PATH1"))
+  (define testingReadPath2 (param "TESTING_READ_PATH2"))
 
   (define (moz-deny feature)
     (if (string=? should-log "TRUE")
       (deny feature)
       (deny feature (with no-log))))
 
   (moz-deny default)
   ; These are not included in (deny default)
@@ -29,38 +34,53 @@ static const char SandboxPolicyGMP[] = R
   (if (defined? 'nvram*)
     (moz-deny nvram*))
   ; This property requires macOS 10.10+
   (if (defined? 'file-map-executable)
     (moz-deny file-map-executable))
 
   (if (defined? 'file-map-executable)
     (allow file-map-executable file-read*
-      (subpath "/System/Library/PrivateFrameworks")
-      (regex #"^/usr/lib/libstdc\+\+\.[^/]*dylib$")
-      (literal plugin-binary-path)
-      (literal app-binary-path)
+      (subpath "/System/Library")
+      (subpath "/usr/lib")
+      (subpath plugin-path)
       (subpath app-path))
     (allow file-read*
-      (subpath "/System/Library/PrivateFrameworks")
-      (regex #"^/usr/lib/libstdc\+\+\.[^/]*dylib$")
-      (literal plugin-binary-path)
-      (literal app-binary-path)
+      (subpath "/System/Library")
+      (subpath "/usr/lib")
+      (subpath plugin-path)
       (subpath app-path)))
 
+  (if (defined? 'file-map-executable)
+    (begin
+      (when plugin-binary-path
+        (allow file-read* file-map-executable (subpath plugin-binary-path)))
+      (when testingReadPath1
+        (allow file-read* file-map-executable (subpath testingReadPath1)))
+      (when testingReadPath2
+        (allow file-read* file-map-executable (subpath testingReadPath2))))
+    (begin
+      (when plugin-binary-path
+        (allow file-read* (subpath plugin-binary-path)))
+      (when testingReadPath1
+        (allow file-read* (subpath testingReadPath1)))
+      (when testingReadPath2
+        (allow file-read* (subpath testingReadPath2)))))
+
+  (if (string? crashPort)
+    (allow mach-lookup (global-name crashPort)))
+
   (allow signal (target self))
   (allow sysctl-read)
   (allow iokit-open (iokit-user-client-class "IOHIDParamUserClient"))
   (allow file-read*
       (literal "/etc")
       (literal "/dev/random")
       (literal "/dev/urandom")
-      (literal "/usr/share/icu/icudt51l.dat")
-      (subpath "/System/Library/Displays/Overrides")
-      (subpath "/System/Library/CoreServices/CoreTypes.bundle"))
+      (literal "/usr/share/icu/icudt51l.dat"))
 
   (if (string=? hasWindowServer "TRUE")
     (allow mach-lookup (global-name "com.apple.windowserver.active")))
 )SANDBOX_LITERAL";
 
 }  // namespace mozilla
 
 #endif  // mozilla_SandboxPolicyGMP_h
--- a/xpcom/base/nsMacUtilsImpl.cpp
+++ b/xpcom/base/nsMacUtilsImpl.cpp
@@ -9,16 +9,17 @@
 #include "base/command_line.h"
 #include "mozilla/ClearOnShutdown.h"
 #include "mozilla/dom/ContentChild.h"
 #include "nsDirectoryServiceDefs.h"
 #include "nsCOMPtr.h"
 #include "nsIFile.h"
 #include "nsIProperties.h"
 #include "nsServiceManagerUtils.h"
+#include "nsThreadUtils.h"
 #include "nsXULAppAPI.h"
 #include "prenv.h"
 
 #if defined(MOZ_SANDBOX)
 #include "mozilla/SandboxSettings.h"
 #endif
 
 #include <CoreFoundation/CoreFoundation.h>
@@ -207,22 +208,35 @@ bool nsMacUtilsImpl::GetAppPath(nsCStrin
   rv = app->Normalize();
   if (NS_FAILED(rv)) {
     return false;
   }
   app->GetNativePath(aAppPath);
 
   if (!sCachedAppPath) {
     sCachedAppPath = new nsCString(aAppPath);
-    ClearOnShutdown(&sCachedAppPath);
+
+    if (NS_IsMainThread()) {
+      nsMacUtilsImpl::ClearCachedAppPathOnShutdown();
+    } else {
+      NS_DispatchToMainThread(NS_NewRunnableFunction(
+          "nsMacUtilsImpl::ClearCachedAppPathOnShutdown",
+          [] { nsMacUtilsImpl::ClearCachedAppPathOnShutdown(); }));
+    }
   }
 
   return true;
 }
 
+nsresult nsMacUtilsImpl::ClearCachedAppPathOnShutdown() {
+  MOZ_ASSERT(NS_IsMainThread());
+  ClearOnShutdown(&sCachedAppPath);
+  return NS_OK;
+}
+
 /*
  * Helper function to read a string value for a given key from the .app's
  * Info.plist.
  */
 static nsresult GetStringValueFromBundlePlist(const nsAString& aKey,
                                               nsAutoCString& aValue) {
   CFBundleRef mainBundle = CFBundleGetMainBundle();
   if (mainBundle == nullptr) {
--- a/xpcom/base/nsMacUtilsImpl.h
+++ b/xpcom/base/nsMacUtilsImpl.h
@@ -53,16 +53,18 @@ class nsMacUtilsImpl final : public nsIM
   // in our binary.
   nsString mBinaryArchs;
 
 #if defined(MOZ_SANDBOX)
   // Cache the appDir returned from GetAppPath to avoid doing I/O
   static StaticAutoPtr<nsCString> sCachedAppPath;
   // For thread safe setting/checking of sCachedAppPath
   static StaticMutex sCachedAppPathMutex;
+  // Utility method to call ClearOnShutdown() on the main thread
+  static nsresult ClearCachedAppPathOnShutdown();
 #endif
 
   enum TCSMStatus { TCSM_Unknown = 0, TCSM_Available, TCSM_Unavailable };
   static mozilla::Atomic<nsMacUtilsImpl::TCSMStatus> sTCSMStatus;
 
   static nsresult EnableTCSM();
 #if defined(DEBUG)
   static bool IsTCSMEnabled();