Bug 1488439: Part 1 - Replace Windows temp folder in sandboxed plugin process (r=bobowen,erahm)
☠☠ backed out by ae464c376e72 ☠ ☠
authorDavid Parks <dparks@mozilla.com>
Wed, 10 Oct 2018 20:16:22 +0000
changeset 499063 6af35f6a050fb97ce23ecde1a937e0c81e8e4c02
parent 499062 300a08d9762e3efcfdedb292d540420ba9c9083f
child 499064 96ae9247bb0f2678cd44b15740da601de25c39ae
push id1864
push userffxbld-merge
push dateMon, 03 Dec 2018 15:51:40 +0000
treeherdermozilla-release@f040763d99ad [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbobowen, erahm
bugs1488439
milestone64.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 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
@@ -1088,22 +1088,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");
         }
     }
+#else if 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
@@ -693,21 +695,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,
@@ -743,16 +740,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 (!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___