Bug 1488439: Part 1 - Replace Windows temp folder in sandboxed plugin process (r=bobowen,erahm)
☠☠ backed out by 32af88ce76da ☠ ☠
authorDavid Parks <dparks@mozilla.com>
Fri, 12 Oct 2018 17:40:10 +0000
changeset 489369 85575fc37555213a204b8565bbadef7270edd19e
parent 489350 067a1c08f91d13f9ad8b7c73b40b2a9065d24c0e
child 489370 b7e586708ecccea803d5c4b77e3f9d7bbcb912f6
push id247
push userfmarier@mozilla.com
push dateSat, 27 Oct 2018 01:06:44 +0000
reviewersbobowen, erahm
bugs1488439
milestone64.0a1
Bug 1488439: Part 1 - Replace Windows temp folder in sandboxed plugin process (r=bobowen,erahm) The sandbox blocks GetTempFileName's prior response, causing the system to end up searching a number of (inaccessible) folders to use as a replacement for the temp folder. This patch provides a path to a new folder on the command line for the plugin process. This new temp folder, specific to this plugin process instance, is then communicated to the system via the TEMP/TMP environment variables. This is similar to what is done for the content process but avoids nsDirectoryService, which doesn't exist in plugin processes. Differential Revision: https://phabricator.services.mozilla.com/D7532
browser/app/profile/firefox.js
dom/plugins/ipc/PluginProcessChild.cpp
dom/plugins/ipc/PluginProcessParent.cpp
security/sandbox/win/src/sandboxbroker/sandboxBroker.cpp
toolkit/xre/nsXREDirProvider.cpp
toolkit/xre/nsXREDirProvider.h
xpcom/io/nsAppDirectoryServiceDefs.h
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -1094,22 +1094,25 @@ pref("security.sandbox.content.syscall_w
 // broad list for now, has to be refined over time
 pref("security.sandbox.pledge.main", "stdio rpath wpath cpath inet proc exec prot_exec flock ps sendfd recvfd dns vminfo tty drm unix fattr getpw mcast");
 #if defined(MOZ_CONTENT_SANDBOX)
 pref("security.sandbox.content.level", 1);
 pref("security.sandbox.pledge.content", "stdio rpath wpath cpath inet recvfd sendfd prot_exec unix drm ps");
 #endif
 #endif
 
-#if defined(MOZ_SANDBOX) && defined(MOZ_CONTENT_SANDBOX)
+#if defined(MOZ_SANDBOX)
+#if defined(MOZ_CONTENT_SANDBOX)
 // ID (a UUID when set by gecko) that is used to form the name of a
 // sandbox-writable temporary directory to be used by content processes
 // when a temporary writable file is required in a level 1 sandbox.
 pref("security.sandbox.content.tempDirSuffix", "");
 #endif
+pref("security.sandbox.plugin.tempDirSuffix", "");
+#endif
 
 #if defined(MOZ_SANDBOX)
 // This pref determines if messages relevant to sandbox violations are
 // logged.
 #if defined(XP_WIN) || defined(XP_MACOSX)
 pref("security.sandbox.logging.enabled", false);
 #endif
 #endif
--- a/dom/plugins/ipc/PluginProcessChild.cpp
+++ b/dom/plugins/ipc/PluginProcessChild.cpp
@@ -24,28 +24,45 @@
 // An undocumented CoreGraphics framework method, present in the same form
 // since at least OS X 10.5.
 extern "C" CGError CGSSetDebugOptions(int options);
 #endif
 
 #ifdef XP_WIN
 #if defined(MOZ_SANDBOX)
 #include "mozilla/sandboxTarget.h"
+#include "ProcessUtils.h"
+#include "nsDirectoryService.h"
 #endif
 #endif
 
 using mozilla::ipc::IOThreadChild;
 
 #ifdef OS_WIN
 #include <algorithm>
 #endif
 
 namespace mozilla {
 namespace plugins {
 
+#if defined(XP_WIN) && defined(MOZ_SANDBOX)
+static void
+SetSandboxTempPath(const std::wstring& aFullTmpPath)
+{
+  // Save the TMP environment variable so that is is picked up by GetTempPath().
+  // Note that we specifically write to the TMP variable, as that is the first
+  // variable that is checked by GetTempPath() to determine its output.
+  Unused << NS_WARN_IF(!SetEnvironmentVariableW(L"TMP", aFullTmpPath.c_str()));
+
+  // We also set TEMP in case there is naughty third-party code that is
+  // referencing the environment variable directly.
+  Unused << NS_WARN_IF(!SetEnvironmentVariableW(L"TEMP", aFullTmpPath.c_str()));
+}
+#endif
+
 bool
 PluginProcessChild::Init(int aArgc, char* aArgv[])
 {
     nsDebugImpl::SetMultiprocessMode("NPAPI");
 
 #if defined(XP_MACOSX)
     // Remove the trigger for "dyld interposing" that we added in
     // GeckoChildProcessHost::PerformAsyncLaunch(), in the host
@@ -114,27 +131,36 @@ PluginProcessChild::Init(int aArgc, char
     }
 #endif
 
 #elif defined(OS_WIN)
     std::vector<std::wstring> values =
         CommandLine::ForCurrentProcess()->GetLooseValues();
     MOZ_ASSERT(values.size() >= 1, "not enough loose args");
 
+    // parameters are:
+    // values[0] is path to plugin DLL
+    // values[1] is path to folder that should be used for temp files
     pluginFilename = WideToUTF8(values[0]);
 
     // We don't initialize XPCOM but we need the thread manager and the
     // logging framework for the FunctionBroker.
     NS_SetMainThread();
     mozilla::TimeStamp::Startup();
     NS_LogInit();
     mozilla::LogModule::Init(aArgc, aArgv);
     nsThreadManager::get().Init();
 
 #if defined(MOZ_SANDBOX)
+    MOZ_ASSERT(values.size() >= 2, "not enough loose args for sandboxed plugin process");
+
+    // The sandbox closes off the default location temp file location so we set
+    // a new one here (regardless of whether or not we are sandboxing).
+    SetSandboxTempPath(values[1]);
+
     // This is probably the earliest we would want to start the sandbox.
     // As we attempt to tighten the sandbox, we may need to consider moving this
     // to later in the plugin initialization.
     mozilla::SandboxTarget::Instance()->StartSandbox();
 #endif
 #else
 #  error Sorry
 #endif
--- a/dom/plugins/ipc/PluginProcessParent.cpp
+++ b/dom/plugins/ipc/PluginProcessParent.cpp
@@ -4,16 +4,21 @@
  * 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 "mozilla/plugins/PluginProcessParent.h"
 
 #include "base/string_util.h"
 #include "base/process_util.h"
 
+#include "nsAppDirectoryServiceDefs.h"
+#include "nsDirectoryServiceDefs.h"
+#include "nsIProperties.h"
+#include "nsServiceManagerUtils.h"
+
 #include "mozilla/ipc/BrowserProcessSubThread.h"
 #include "mozilla/plugins/PluginMessageUtils.h"
 #include "mozilla/Telemetry.h"
 #include "nsThreadUtils.h"
 
 using std::vector;
 using std::string;
 
@@ -83,16 +88,37 @@ PluginProcessParent::Launch(mozilla::Uni
 #if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
     if (aSandboxLevel > 0) {
         args.push_back("-flashSandboxLevel");
         args.push_back(std::to_string(aSandboxLevel));
         if (aIsSandboxLoggingEnabled) {
             args.push_back("-flashSandboxLogging");
         }
     }
+#elseif defined(XP_WIN) && defined(MOZ_SANDBOX)
+    nsresult rv;
+    nsCOMPtr<nsIProperties> dirSvc =
+      do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID, &rv);
+    if (NS_FAILED(rv)) {
+      MOZ_ASSERT(false, "Failed to get directory service.");
+      return false;
+    }
+
+    nsCOMPtr<nsIFile> dir;
+    rv =
+      dirSvc->Get(NS_APP_PLUGIN_PROCESS_TEMP_DIR, NS_GET_IID(nsIFile),
+                  getter_AddRefs(dir));
+    if (NS_FAILED(rv)) {
+      NS_WARNING("Failed to get plugin process temp directory.");
+      return false;
+    }
+
+    nsAutoString tempDir;
+    MOZ_ALWAYS_SUCCEEDS(dir->GetPath(tempDir));
+    args.push_back(NS_ConvertUTF16toUTF8(tempDir).get());
 #endif
 
     bool result = AsyncLaunch(args);
     if (!result) {
         mLaunchCompleteTask = nullptr;
     }
     return result;
 }
--- a/security/sandbox/win/src/sandboxbroker/sandboxBroker.cpp
+++ b/security/sandbox/win/src/sandboxbroker/sandboxBroker.cpp
@@ -39,16 +39,17 @@ sandbox::BrokerServices *SandboxBroker::
 // fundamental things when running from a network drive. We default to false in
 // case those checks fail as that gives us the strongest policy.
 bool SandboxBroker::sRunningFromNetworkDrive = false;
 
 // Cached special directories used for adding policy rules.
 static UniquePtr<nsString> sBinDir;
 static UniquePtr<nsString> sProfileDir;
 static UniquePtr<nsString> sContentTempDir;
+static UniquePtr<nsString> sPluginTempDir;
 static UniquePtr<nsString> sRoamingAppDataDir;
 static UniquePtr<nsString> sLocalAppDataDir;
 static UniquePtr<nsString> sUserExtensionsDevDir;
 #ifdef ENABLE_SYSTEM_EXTENSION_DIRS
 static UniquePtr<nsString> sUserExtensionsDir;
 #endif
 
 // Cached prefs which are needed off main thread.
@@ -110,16 +111,17 @@ SandboxBroker::GeckoDependentInitialize(
     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
 
   // Create sLaunchErrors up front because ClearOnShutdown must be called on the
@@ -694,21 +696,16 @@ SandboxBroker::SetSecurityLevelForPlugin
     delayedIntegrityLevel = sandbox::INTEGRITY_LEVEL_LOW;
   } else {
     jobLevel = sandbox::JOB_NONE;
     accessTokenLevel = sandbox::USER_NON_ADMIN;
     initialIntegrityLevel = sandbox::INTEGRITY_LEVEL_MEDIUM;
     delayedIntegrityLevel = sandbox::INTEGRITY_LEVEL_MEDIUM;
   }
 
-#ifndef NIGHTLY_BUILD
-  // We are experimenting with using restricting SIDs in the nightly builds
-  mPolicy->SetDoNotUseRestrictingSIDs();
-#endif
-
   sandbox::ResultCode result = SetJobLevel(mPolicy, jobLevel,
                                            0 /* ui_exceptions */);
   SANDBOX_ENSURE_SUCCESS(result,
                          "Setting job level failed, have you set memory limit when jobLevel == JOB_NONE?");
 
   result = mPolicy->SetTokenLevel(sandbox::USER_RESTRICTED_SAME_ACCESS,
                                   accessTokenLevel);
   SANDBOX_ENSURE_SUCCESS(result,
@@ -744,16 +741,25 @@ SandboxBroker::SetSecurityLevelForPlugin
 
   sandbox::MitigationFlags delayedMitigations =
     sandbox::MITIGATION_DLL_SEARCH_ORDER;
 
   result = mPolicy->SetDelayedProcessMitigations(delayedMitigations);
   SANDBOX_ENSURE_SUCCESS(result,
                          "Invalid flags for SetDelayedProcessMitigations.");
 
+#ifndef NIGHTLY_BUILD
+  // We are experimenting with using restricting SIDs in the nightly builds
+  mPolicy->SetDoNotUseRestrictingSIDs();
+#else
+  // Add rule to allow read / write access to a special plugin temp dir.
+  AddCachedDirRule(mPolicy, sandbox::TargetPolicy::FILES_ALLOW_ANY,
+                   sPluginTempDir, NS_LITERAL_STRING("\\*"));
+#endif
+
   if (aSandboxLevel >= 2) {
     // Level 2 and above uses low integrity, so we need to give write access to
     // the Flash directories.
     AddCachedDirRule(mPolicy, sandbox::TargetPolicy::FILES_ALLOW_ANY,
                      sRoamingAppDataDir,
                      NS_LITERAL_STRING("\\Macromedia\\Flash Player\\*"));
     AddCachedDirRule(mPolicy, sandbox::TargetPolicy::FILES_ALLOW_ANY,
                      sLocalAppDataDir,
--- a/toolkit/xre/nsXREDirProvider.cpp
+++ b/toolkit/xre/nsXREDirProvider.cpp
@@ -77,21 +77,21 @@
 #define APP_REGISTRY_NAME "registry.dat"
 #else
 #define APP_REGISTRY_NAME "appreg"
 #endif
 
 #define PREF_OVERRIDE_DIRNAME "preferences"
 
 #if defined(MOZ_CONTENT_SANDBOX)
-static already_AddRefed<nsIFile> GetContentProcessSandboxTempDir();
+static already_AddRefed<nsIFile> GetProcessSandboxTempDir(GeckoProcessType type);
 static nsresult DeleteDirIfExists(nsIFile *dir);
 static bool IsContentSandboxDisabled();
-static const char* GetContentProcessTempBaseDirKey();
-static already_AddRefed<nsIFile> CreateContentProcessSandboxTempDir();
+static const char* GetProcessTempBaseDirKey();
+static already_AddRefed<nsIFile> CreateProcessSandboxTempDir(GeckoProcessType procType);
 #endif
 
 nsXREDirProvider* gDirServiceProvider = nullptr;
 nsIFile* gDataDirHomeLocal = nullptr;
 nsIFile* gDataDirHome = nullptr;
 
 // These are required to allow nsXREDirProvider to be usable in xpcshell tests.
 // where gAppData is null.
@@ -521,17 +521,25 @@ nsXREDirProvider::GetFile(const char* aP
   }
 #if defined(MOZ_CONTENT_SANDBOX)
   else if (!strcmp(aProperty, NS_APP_CONTENT_PROCESS_TEMP_DIR)) {
     if (!mContentTempDir && NS_FAILED((rv = LoadContentProcessTempDir()))) {
       return rv;
     }
     rv = mContentTempDir->Clone(getter_AddRefs(file));
   }
-#endif // defined(XP_WIN) && defined(MOZ_CONTENT_SANDBOX)
+#endif // defined(MOZ_CONTENT_SANDBOX)
+#if defined(MOZ_SANDBOX)
+  else if (0 == strcmp(aProperty, NS_APP_PLUGIN_PROCESS_TEMP_DIR)) {
+    if (!mPluginTempDir && NS_FAILED((rv = LoadPluginProcessTempDir()))) {
+      return rv;
+    }
+    rv = mPluginTempDir->Clone(getter_AddRefs(file));
+  }
+#endif // defined(MOZ_SANDBOX)
   else if (NS_SUCCEEDED(GetProfileStartupDir(getter_AddRefs(file)))) {
     // We need to allow component, xpt, and chrome registration to
     // occur prior to the profile-after-change notification.
     if (!strcmp(aProperty, NS_APP_USER_CHROME_DIR)) {
       rv = file->AppendNative(NS_LITERAL_CSTRING("chrome"));
     }
   }
 
@@ -661,42 +669,47 @@ nsXREDirProvider::GetFiles(const char* a
 
   rv = NS_NewUnionEnumerator(aResult, appEnum, xreEnum);
   if (NS_FAILED(rv))
     return rv;
 
   return NS_SUCCESS_AGGREGATE_RESULT;
 }
 
-#if defined(MOZ_CONTENT_SANDBOX)
+#if defined(MOZ_SANDBOX)
 
 static const char*
-GetContentProcessTempBaseDirKey()
+GetProcessTempBaseDirKey()
 {
 #if defined(XP_WIN)
   return NS_WIN_LOW_INTEGRITY_TEMP_BASE;
 #else
   return NS_OS_TEMP_DIR;
 #endif
 }
 
+#if defined(MOZ_CONTENT_SANDBOX)
 //
 // Sets mContentTempDir so that it refers to the appropriate temp dir.
 // If the sandbox is enabled, NS_APP_CONTENT_PROCESS_TEMP_DIR, otherwise
 // NS_OS_TEMP_DIR is used.
 //
 nsresult
 nsXREDirProvider::LoadContentProcessTempDir()
 {
   // The parent is responsible for creating the sandbox temp dir.
   if (XRE_IsParentProcess()) {
-    mContentProcessSandboxTempDir = CreateContentProcessSandboxTempDir();
+    mContentProcessSandboxTempDir =
+      CreateProcessSandboxTempDir(GeckoProcessType_Content);
     mContentTempDir = mContentProcessSandboxTempDir;
   } else {
-    mContentTempDir = GetContentProcessSandboxTempDir();
+    mContentTempDir =
+      !IsContentSandboxDisabled() ?
+        GetProcessSandboxTempDir(GeckoProcessType_Content) :
+        nullptr;
   }
 
   if (!mContentTempDir) {
     nsresult rv = NS_GetSpecialDirectory(NS_OS_TEMP_DIR,
                                          getter_AddRefs(mContentTempDir));
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
@@ -708,76 +721,127 @@ nsXREDirProvider::LoadContentProcessTemp
   // reject those rules.
   if (!mozilla::widget::WinUtils::ResolveJunctionPointsAndSymLinks(mContentTempDir)) {
     NS_WARNING("Failed to resolve Content Temp Dir.");
   }
 #endif
 
   return NS_OK;
 }
+#endif
+
+//
+// Sets mPluginTempDir so that it refers to the appropriate temp dir.
+// If NS_APP_PLUGIN_PROCESS_TEMP_DIR fails for any reason, NS_OS_TEMP_DIR
+// is used.
+//
+nsresult
+nsXREDirProvider::LoadPluginProcessTempDir()
+{
+  // The parent is responsible for creating the sandbox temp dir.
+  if (XRE_IsParentProcess()) {
+    mPluginProcessSandboxTempDir =
+      CreateProcessSandboxTempDir(GeckoProcessType_Plugin);
+    mPluginTempDir = mPluginProcessSandboxTempDir;
+  } else {
+    MOZ_ASSERT(XRE_IsPluginProcess());
+    mPluginTempDir = GetProcessSandboxTempDir(GeckoProcessType_Plugin);
+  }
+
+  if (!mPluginTempDir) {
+    nsresult rv = NS_GetSpecialDirectory(NS_OS_TEMP_DIR,
+                                         getter_AddRefs(mPluginTempDir));
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+    }
+  }
+
+#if defined(XP_WIN)
+  // The temp dir is used in sandbox rules, so we need to make sure
+  // it doesn't contain any junction points or symlinks or the sandbox will
+  // reject those rules.
+  if (!mozilla::widget::WinUtils::ResolveJunctionPointsAndSymLinks(mPluginTempDir)) {
+    NS_WARNING("Failed to resolve plugin temp dir.");
+  }
+#endif
+
+  return NS_OK;
+}
 
 static bool
 IsContentSandboxDisabled()
 {
   return !BrowserTabsRemoteAutostart() || (!IsContentSandboxEnabled());
 }
 
 //
-// If a content process sandbox temp dir is to be used, returns an nsIFile
-// for the directory. Returns null if the content sandbox is disabled or
-// an error occurs.
+// If a process sandbox temp dir is to be used, returns an nsIFile
+// for the directory. Returns null if an error occurs.
 //
 static already_AddRefed<nsIFile>
-GetContentProcessSandboxTempDir()
+GetProcessSandboxTempDir(GeckoProcessType type)
 {
-  if (IsContentSandboxDisabled()) {
-    return nullptr;
-  }
-
   nsCOMPtr<nsIFile> localFile;
 
-  nsresult rv = NS_GetSpecialDirectory(GetContentProcessTempBaseDirKey(),
+  nsresult rv = NS_GetSpecialDirectory(GetProcessTempBaseDirKey(),
                                        getter_AddRefs(localFile));
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return nullptr;
   }
 
+  MOZ_ASSERT((type == GeckoProcessType_Content) ||
+             (type == GeckoProcessType_Plugin));
+
+  const char* prefKey =
+    (type == GeckoProcessType_Content) ?
+      "security.sandbox.content.tempDirSuffix" :
+      "security.sandbox.plugin.tempDirSuffix";
+
   nsAutoString tempDirSuffix;
-  rv = Preferences::GetString("security.sandbox.content.tempDirSuffix",
-                              tempDirSuffix);
+  rv = Preferences::GetString(prefKey, tempDirSuffix);
   if (NS_WARN_IF(NS_FAILED(rv)) || tempDirSuffix.IsEmpty()) {
     return nullptr;
   }
 
   rv = localFile->Append(NS_LITERAL_STRING("Temp-") + tempDirSuffix);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return nullptr;
   }
 
   return localFile.forget();
 }
 
 //
-// Create a temporary directory for use from sandboxed content processes.
+// Create a temporary directory for use from sandboxed processes.
 // Only called in the parent. The path is derived from a UUID stored in a
-// pref which is available to content processes. Returns null if the
-// content sandbox is disabled or if an error occurs.
+// pref which is available to content and plugin processes. Returns null
+// if the content sandbox is disabled or if an error occurs.
 //
 static already_AddRefed<nsIFile>
-CreateContentProcessSandboxTempDir()
+CreateProcessSandboxTempDir(GeckoProcessType procType)
 {
-  if (IsContentSandboxDisabled()) {
+#if defined(MOZ_CONTENT_SANDBOX)
+  if ((procType == GeckoProcessType_Content) &&
+      IsContentSandboxDisabled()) {
     return nullptr;
   }
+#endif
+
+  MOZ_ASSERT((procType == GeckoProcessType_Content) ||
+             (procType == GeckoProcessType_Plugin));
 
   // Get (and create if blank) temp directory suffix pref.
+  const char* pref =
+    (procType == GeckoProcessType_Content) ?
+      "security.sandbox.content.tempDirSuffix" :
+      "security.sandbox.plugin.tempDirSuffix";
+
   nsresult rv;
   nsAutoString tempDirSuffix;
-  Preferences::GetString("security.sandbox.content.tempDirSuffix",
-                         tempDirSuffix);
+  Preferences::GetString(pref, tempDirSuffix);
   if (tempDirSuffix.IsEmpty()) {
     nsCOMPtr<nsIUUIDGenerator> uuidgen =
       do_GetService("@mozilla.org/uuid-generator;1", &rv);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return nullptr;
     }
 
     nsID uuid;
@@ -791,18 +855,17 @@ CreateContentProcessSandboxTempDir()
     tempDirSuffix.AssignASCII(uuidChars, NSID_LENGTH);
 #ifdef XP_UNIX
     // Braces in a path are somewhat annoying to deal with
     // and pretty alien on Unix
     tempDirSuffix.StripChars(u"{}");
 #endif
 
     // Save the pref
-    rv = Preferences::SetString("security.sandbox.content.tempDirSuffix",
-                                tempDirSuffix);
+    rv = Preferences::SetString(pref, tempDirSuffix);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       // If we fail to save the pref we don't want to create the temp dir,
       // because we won't be able to clean it up later.
       return nullptr;
     }
 
     nsCOMPtr<nsIPrefService> prefsvc = Preferences::GetService();
     if (!prefsvc || NS_FAILED((rv = prefsvc->SavePrefFile(nullptr)))) {
@@ -811,17 +874,17 @@ CreateContentProcessSandboxTempDir()
       // the preference values allows an off main thread save, the successful
       // return from the call doesn't mean we actually saved the file.  See
       // bug 1364496 for details.
       NS_WARNING("Failed to save pref file, cannot create temp dir.");
       return nullptr;
     }
   }
 
-  nsCOMPtr<nsIFile> sandboxTempDir = GetContentProcessSandboxTempDir();
+  nsCOMPtr<nsIFile> sandboxTempDir = GetProcessSandboxTempDir(procType);
   if (!sandboxTempDir) {
     NS_WARNING("Failed to determine sandbox temp dir path.");
     return nullptr;
   }
 
   // Remove the directory. It may exist due to a previous crash.
   if (NS_FAILED(DeleteDirIfExists(sandboxTempDir))) {
     NS_WARNING("Failed to reset sandbox temp dir.");
@@ -849,17 +912,17 @@ DeleteDirIfExists(nsIFile* dir)
     if (NS_FAILED(rv) && rv != NS_ERROR_FILE_NOT_FOUND &&
         rv != NS_ERROR_FILE_TARGET_DOES_NOT_EXIST) {
       return rv;
     }
   }
   return NS_OK;
 }
 
-#endif // defined(MOZ_CONTENT_SANDBOX)
+#endif // defined(MOZ_SANDBOX)
 
 static const char *const kAppendPrefDir[] = { "defaults", "preferences", nullptr };
 
 #ifdef DEBUG_bsmedberg
 static void
 DumpFileArray(const char *key,
               nsCOMArray<nsIFile> dirs)
 {
@@ -1070,16 +1133,21 @@ nsXREDirProvider::DoStartup()
 #if defined(MOZ_CONTENT_SANDBOX)
     // Makes sure the content temp dir has been loaded if it hasn't been
     // already. In the parent this ensures it has been created before we attempt
     // to start any content processes.
     if (!mContentTempDir) {
       mozilla::Unused << NS_WARN_IF(NS_FAILED(LoadContentProcessTempDir()));
     }
 #endif
+#if defined(MOZ_SANDBOX)
+    if (!mPluginTempDir) {
+      mozilla::Unused << NS_WARN_IF(NS_FAILED(LoadPluginProcessTempDir()));
+    }
+#endif
   }
   return NS_OK;
 }
 
 void
 nsXREDirProvider::DoShutdown()
 {
   AUTO_PROFILER_LABEL("nsXREDirProvider::DoShutdown", OTHER);
@@ -1102,21 +1170,24 @@ nsXREDirProvider::DoShutdown()
 
       obsSvc->NotifyObservers(nullptr, "profile-before-change", kShutdownPersist);
       obsSvc->NotifyObservers(nullptr, "profile-before-change-qm", kShutdownPersist);
       obsSvc->NotifyObservers(nullptr, "profile-before-change-telemetry", kShutdownPersist);
     }
     mProfileNotified = false;
   }
 
+  if (XRE_IsParentProcess()) {
 #if defined(MOZ_CONTENT_SANDBOX)
-  if (XRE_IsParentProcess()) {
     Unused << DeleteDirIfExists(mContentProcessSandboxTempDir);
+#endif
+#if defined(MOZ_SANDBOX)
+    Unused << DeleteDirIfExists(mPluginProcessSandboxTempDir);
+#endif
   }
-#endif
 }
 
 #ifdef XP_WIN
 static nsresult
 GetShellFolderPath(KNOWNFOLDERID folder, nsAString& _retval)
 {
   DWORD flags = KF_FLAG_SIMPLE_IDLIST | KF_FLAG_DONT_VERIFY | KF_FLAG_NO_ALIAS;
   PWSTR path = nullptr;
--- a/toolkit/xre/nsXREDirProvider.h
+++ b/toolkit/xre/nsXREDirProvider.h
@@ -124,16 +124,19 @@ protected:
   // Internal helper that splits a path into components using the '/' and '\\'
   // delimiters.
   static inline nsresult AppendProfileString(nsIFile* aFile, const char* aPath);
 
 #if defined(MOZ_CONTENT_SANDBOX)
   // Load the temp directory for sandboxed content processes
   nsresult LoadContentProcessTempDir();
 #endif
+#if defined(MOZ_SANDBOX)
+  nsresult LoadPluginProcessTempDir();
+#endif
 
   void Append(nsIFile* aDirectory);
 
   nsCOMPtr<nsIDirectoryServiceProvider> mAppProvider;
   // On OSX, mGREDir points to .app/Contents/Resources
   nsCOMPtr<nsIFile>      mGREDir;
   // On OSX, mGREBinDir points to .app/Contents/MacOS
   nsCOMPtr<nsIFile>      mGREBinDir;
@@ -142,12 +145,16 @@ protected:
   nsCOMPtr<nsIFile>      mProfileDir;
   nsCOMPtr<nsIFile>      mProfileLocalDir;
   bool                   mProfileNotified;
   bool                   mPrefsInitialized = false;
 #if defined(MOZ_CONTENT_SANDBOX)
   nsCOMPtr<nsIFile>      mContentTempDir;
   nsCOMPtr<nsIFile>      mContentProcessSandboxTempDir;
 #endif
+#if defined(MOZ_SANDBOX)
+  nsCOMPtr<nsIFile>      mPluginTempDir;
+  nsCOMPtr<nsIFile>      mPluginProcessSandboxTempDir;
+#endif
   nsCOMArray<nsIFile>    mAppBundleDirectories;
 };
 
 #endif
--- a/xpcom/io/nsAppDirectoryServiceDefs.h
+++ b/xpcom/io/nsAppDirectoryServiceDefs.h
@@ -98,11 +98,17 @@
 //
 // At present, all sandboxed content processes use the same directory for
 // NS_APP_CONTENT_PROCESS_TEMP_DIR, but that should not be relied upon.
 //
 #define NS_APP_CONTENT_PROCESS_TEMP_DIR         "ContentTmpD"
 #else
 // Otherwise NS_APP_CONTENT_PROCESS_TEMP_DIR must match NS_OS_TEMP_DIR.
 #define NS_APP_CONTENT_PROCESS_TEMP_DIR         "TmpD"
-#endif // (defined(XP_WIN) || defined(XP_MACOSX)) && defined(MOZ_CONTENT_SANDBOX)
+#endif // defined(MOZ_CONTENT_SANDBOX)
+
+#if defined(MOZ_SANDBOX)
+#define NS_APP_PLUGIN_PROCESS_TEMP_DIR          "PluginTmpD"
+#else
+#define NS_APP_PLUGIN_PROCESS_TEMP_DIR          "TmpD"
+#endif
 
 #endif // nsAppDirectoryServiceDefs_h___