Bug 1386404 - Enable content-process specific tmpdir on Linux. r=haik
☠☠ backed out by 1aa6d3251c70 ☠ ☠
authorGian-Carlo Pascutto <gcp@mozilla.com>
Thu, 12 Oct 2017 11:18:25 +0200
changeset 443366 d7f697bac6efc9a3c64d76137eb653aab9601b8b
parent 443365 f7af48305978405e52c1b61920b3a51746249579
child 443367 802a00ea50e785d2fccce7d3035b84dcdfa6cadb
push id1618
push userCallek@gmail.com
push dateThu, 11 Jan 2018 17:45:48 +0000
treeherdermozilla-release@882ca853e05a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewershaik
bugs1386404
milestone58.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 1386404 - Enable content-process specific tmpdir on Linux. r=haik MozReview-Commit-ID: 6Hijq0to9MG
browser/app/profile/firefox.js
ipc/glue/GeckoChildProcessHost.cpp
ipc/glue/GeckoChildProcessHost.h
security/sandbox/linux/broker/SandboxBrokerPolicyFactory.cpp
security/sandbox/test/browser_content_sandbox_fs.js
security/sandbox/test/browser_content_sandbox_utils.js
toolkit/xre/nsXREDirProvider.cpp
toolkit/xre/nsXREDirProvider.h
xpcom/io/nsAppDirectoryServiceDefs.h
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -1102,24 +1102,22 @@ pref("security.sandbox.content.level", 3
 // This setting may not be required anymore once we decide to permanently
 // enable the content sandbox.
 pref("security.sandbox.content.level", 3);
 pref("security.sandbox.content.write_path_whitelist", "");
 pref("security.sandbox.content.read_path_whitelist", "");
 pref("security.sandbox.content.syscall_whitelist", "");
 #endif
 
-#if defined(XP_MACOSX) || defined(XP_WIN)
 #if defined(MOZ_SANDBOX) && 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
-#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);
 #else
 pref("security.sandbox.logging.enabled", true);
--- a/ipc/glue/GeckoChildProcessHost.cpp
+++ b/ipc/glue/GeckoChildProcessHost.cpp
@@ -20,31 +20,30 @@
 
 #include "MainThreadUtils.h"
 #include "mozilla/Sprintf.h"
 #include "prenv.h"
 #include "nsXPCOMPrivate.h"
 
 #if defined(MOZ_CONTENT_SANDBOX)
 #include "mozilla/SandboxSettings.h"
-#if defined(XP_MACOSX)
 #include "nsAppDirectoryServiceDefs.h"
 #endif
-#endif
 
 #include "nsExceptionHandler.h"
 
 #include "nsDirectoryServiceDefs.h"
 #include "nsIFile.h"
 #include "nsPrintfCString.h"
 
 #include "mozilla/ClearOnShutdown.h"
 #include "mozilla/ipc/BrowserProcessSubThread.h"
 #include "mozilla/Omnijar.h"
 #include "mozilla/Telemetry.h"
+#include "mozilla/Maybe.h"
 #include "ProtocolUtils.h"
 #include <sys/stat.h>
 
 #ifdef XP_WIN
 #include "nsIWinTaskbar.h"
 #include <stdlib.h>
 #define NS_TASKBAR_CONTRACTID "@mozilla.org/windows-taskbar;1"
 
@@ -432,25 +431,23 @@ GeckoChildProcessHost::SetAlreadyDead()
   }
 
   mChildProcessHandle = 0;
 }
 
 int32_t GeckoChildProcessHost::mChildCounter = 0;
 
 void
-GeckoChildProcessHost::SetChildLogName(const char* varName, const char* origLogName,
+GeckoChildProcessHost::GetChildLogName(const char* origLogName,
                                        nsACString &buffer)
 {
   // We currently have no portable way to launch child with environment
   // different than parent.  So temporarily change NSPR_LOG_FILE so child
   // inherits value we want it to have. (NSPR only looks at NSPR_LOG_FILE at
   // startup, so it's 'safe' to play with the parent's environment this way.)
-  buffer.Assign(varName);
-
 #ifdef XP_WIN
   // On Windows we must expand relative paths because sandboxing rules
   // bound only to full paths.  fopen fowards to NtCreateFile which checks
   // the path against the sanboxing rules as passed to fopen (left relative).
   char absPath[MAX_PATH + 2];
   if (_fullpath(absPath, origLogName, sizeof(absPath))) {
 #ifdef MOZ_SANDBOX
     // We need to make sure the child log name doesn't contain any junction
@@ -467,85 +464,108 @@ GeckoChildProcessHost::SetChildLogName(c
 #endif
   {
     buffer.Append(origLogName);
   }
 
   // Append child-specific postfix to name
   buffer.AppendLiteral(".child-");
   buffer.AppendInt(mChildCounter);
+}
 
-  // Passing temporary to PR_SetEnv is ok here if we keep the temporary
-  // for the time we launch the sub-process.  It's copied to the new
-  // environment.
-  PR_SetEnv(buffer.BeginReading());
-}
+class AutoSetAndRestoreEnvVarForChildProcess {
+public:
+  AutoSetAndRestoreEnvVarForChildProcess(const char* envVar,
+                                         const char* newVal) {
+    const char* origVal = PR_GetEnv(envVar);
+    mSetString.Assign(envVar);
+    mSetString.Append('=');
+    mRestoreString.Assign(mSetString);
+
+    mSetString.Append(newVal);
+    mRestoreString.Append(origVal);
+
+    // Passing to PR_SetEnv is ok here if we keep the the storage alive
+    // for the time we launch the sub-process.  It's copied to the new
+    // environment by PR_DuplicateEnvironment()
+    PR_SetEnv(mSetString.get());
+  }
+  // Delegate helper
+  AutoSetAndRestoreEnvVarForChildProcess(const char* envVar,
+                                         nsCString& newVal)
+    : AutoSetAndRestoreEnvVarForChildProcess(envVar, newVal.get()) {}
+  ~AutoSetAndRestoreEnvVarForChildProcess() {
+    PR_SetEnv(mRestoreString.get());
+  }
+private:
+  nsAutoCString mSetString;
+  nsAutoCString mRestoreString;
+};
 
 bool
 GeckoChildProcessHost::PerformAsyncLaunch(std::vector<std::string> aExtraOpts)
 {
 #ifdef MOZ_GECKO_PROFILER
   AutoSetProfilerEnvVarsForChildProcess profilerEnvironment;
 #endif
-
-  const char* origNSPRLogName = PR_GetEnv("NSPR_LOG_FILE");
-  const char* origMozLogName = PR_GetEnv("MOZ_LOG_FILE");
-  const char* origRustLog = PR_GetEnv("RUST_LOG");
-  const char* childRustLog = PR_GetEnv("RUST_LOG_CHILD");
-
   // - Note: this code is not called re-entrantly, nor are restoreOrig*LogName
   //   or mChildCounter touched by any other thread, so this is safe.
   ++mChildCounter;
 
   // Must keep these on the same stack where from we call PerformAsyncLaunchInternal
   // so that PR_DuplicateEnvironment() still sees a valid memory.
-  nsAutoCString nsprLogName;
-  nsAutoCString mozLogName;
-  nsAutoCString rustLog;
+  Maybe<AutoSetAndRestoreEnvVarForChildProcess> nsprLogDir;
+  Maybe<AutoSetAndRestoreEnvVarForChildProcess> mozLogDir;
+  Maybe<AutoSetAndRestoreEnvVarForChildProcess> rustLogDir;
+
+  const char* origNSPRLogName = PR_GetEnv("NSPR_LOG_FILE");
+  const char* origMozLogName = PR_GetEnv("MOZ_LOG_FILE");
 
   if (origNSPRLogName) {
-    if (mRestoreOrigNSPRLogName.IsEmpty()) {
-      mRestoreOrigNSPRLogName.AssignLiteral("NSPR_LOG_FILE=");
-      mRestoreOrigNSPRLogName.Append(origNSPRLogName);
-    }
-    SetChildLogName("NSPR_LOG_FILE=", origNSPRLogName, nsprLogName);
+    nsAutoCString nsprLogName;
+    GetChildLogName(origNSPRLogName, nsprLogName);
+    nsprLogDir.emplace("NSPR_LOG_FILE", nsprLogName);
   }
   if (origMozLogName) {
-    if (mRestoreOrigMozLogName.IsEmpty()) {
-      mRestoreOrigMozLogName.AssignLiteral("MOZ_LOG_FILE=");
-      mRestoreOrigMozLogName.Append(origMozLogName);
-    }
-    SetChildLogName("MOZ_LOG_FILE=", origMozLogName, mozLogName);
+    nsAutoCString mozLogName;
+    GetChildLogName(origMozLogName, mozLogName);
+    mozLogDir.emplace("MOZ_LOG_FILE", mozLogName);
   }
 
   // `RUST_LOG_CHILD` is meant for logging child processes only.
+  const char* childRustLog = PR_GetEnv("RUST_LOG_CHILD");
   if (childRustLog) {
-    if (mRestoreOrigRustLog.IsEmpty()) {
-      mRestoreOrigRustLog.AssignLiteral("RUST_LOG=");
-      mRestoreOrigRustLog.Append(origRustLog);
-    }
-    rustLog.AssignLiteral("RUST_LOG=");
-    rustLog.Append(childRustLog);
-    PR_SetEnv(rustLog.get());
+    rustLogDir.emplace("RUST_LOG", childRustLog);
   }
 
-  bool retval = PerformAsyncLaunchInternal(aExtraOpts);
+#if defined(MOZ_CONTENT_SANDBOX)
+  Maybe<AutoSetAndRestoreEnvVarForChildProcess> tmpDir;
+  Maybe<AutoSetAndRestoreEnvVarForChildProcess> xdgCacheHome;
+  Maybe<AutoSetAndRestoreEnvVarForChildProcess> xdgCacheDir;
+  Maybe<AutoSetAndRestoreEnvVarForChildProcess> mesaCacheDir;
 
-  // Revert to original value
-  if (origNSPRLogName) {
-    PR_SetEnv(mRestoreOrigNSPRLogName.get());
+  nsAutoCString tmpDirName;
+  nsCOMPtr<nsIFile> mContentTempDir;
+  nsresult rv = NS_GetSpecialDirectory(NS_APP_CONTENT_PROCESS_TEMP_DIR,
+                                       getter_AddRefs(mContentTempDir));
+  if (NS_SUCCEEDED(rv)) {
+    rv = mContentTempDir->GetNativePath(tmpDirName);
+    if (NS_SUCCEEDED(rv)) {
+      // Point a bunch of things that might want to write from content to our
+      // shiny new content-process specific tmpdir
+      tmpDir.emplace("TMPDIR", tmpDirName);
+      xdgCacheHome.emplace("XDG_CACHE_HOME", tmpDirName);
+      xdgCacheDir.emplace("XDG_CACHE_DIR", tmpDirName);
+      // Partial fix for bug 1380051 (not persistent - should be)
+      mesaCacheDir.emplace("MESA_GLSL_CACHE_DIR", tmpDirName);
+    }
   }
-  if (origMozLogName) {
-    PR_SetEnv(mRestoreOrigMozLogName.get());
-  }
-  if (origRustLog) {
-    PR_SetEnv(mRestoreOrigRustLog.get());
-  }
+#endif
 
-  return retval;
+  return PerformAsyncLaunchInternal(aExtraOpts);
 }
 
 bool
 GeckoChildProcessHost::RunPerformAsyncLaunch(std::vector<std::string> aExtraOpts)
 {
   InitializeChannel();
 
   bool ok = PerformAsyncLaunch(aExtraOpts);
--- a/ipc/glue/GeckoChildProcessHost.h
+++ b/ipc/glue/GeckoChildProcessHost.h
@@ -175,18 +175,17 @@ private:
     Self,
     PluginContainer
   };
 
   static BinaryPathType GetPathToBinary(FilePath& exePath, GeckoProcessType processType);
 
   // The buffer is passed to preserve its lifetime until we are done
   // with launching the sub-process.
-  void SetChildLogName(const char* varName, const char* origLogName,
-                       nsACString &buffer);
+  void GetChildLogName(const char* origLogName, nsACString &buffer);
 
   // In between launching the subprocess and handing off its IPC
   // channel, there's a small window of time in which *we* might still
   // be the channel listener, and receive messages.  That's bad
   // because we have no idea what to do with those messages.  So queue
   // them here until we hand off the eventual listener.
   //
   // FIXME/cjones: this strongly indicates bad design.  Shame on us.
--- a/security/sandbox/linux/broker/SandboxBrokerPolicyFactory.cpp
+++ b/security/sandbox/linux/broker/SandboxBrokerPolicyFactory.cpp
@@ -181,35 +181,16 @@ SandboxBrokerPolicyFactory::SandboxBroke
 {
   // Policy entries that are the same in every process go here, and
   // are cached over the lifetime of the factory.
 #if defined(MOZ_CONTENT_SANDBOX)
   SandboxBroker::Policy* policy = new SandboxBroker::Policy;
   policy->AddDir(rdwrcr, "/dev/shm");
   // Write permssions
   //
-  // Add write permissions on the temporary directory. This can come
-  // from various environment variables (TMPDIR,TMP,TEMP,...) so
-  // make sure to use the full logic.
-  nsCOMPtr<nsIFile> tmpDir;
-  nsresult rv = GetSpecialSystemDirectory(OS_TemporaryDirectory,
-                                          getter_AddRefs(tmpDir));
-
-  if (NS_SUCCEEDED(rv)) {
-    nsAutoCString tmpPath;
-    rv = tmpDir->GetNativePath(tmpPath);
-    if (NS_SUCCEEDED(rv)) {
-      policy->AddDir(rdwrcr, tmpPath.get());
-    }
-  }
-  // If the above fails at any point, fall back to a very good guess.
-  if (NS_FAILED(rv)) {
-    policy->AddDir(rdwrcr, "/tmp");
-  }
-
   // Bug 1308851: NVIDIA proprietary driver when using WebGL
   policy->AddFilePrefix(rdwr, "/dev", "nvidia");
 
   // Bug 1312678: radeonsi/Intel with DRI when using WebGL
   policy->AddDir(rdwr, "/dev/dri");
 
 #ifdef MOZ_ALSA
   // Bug 1309098: ALSA support
@@ -285,17 +266,18 @@ SandboxBrokerPolicyFactory::SandboxBroke
   // access to.
   mozilla::Array<const char*, 3> extraConfDirs = {
     ".config",   // Fallback if XDG_CONFIG_PATH isn't set
     ".themes",
     ".fonts",
   };
 
   nsCOMPtr<nsIFile> homeDir;
-  rv = GetSpecialSystemDirectory(Unix_HomeDirectory, getter_AddRefs(homeDir));
+  nsresult rv = GetSpecialSystemDirectory(Unix_HomeDirectory,
+                                          getter_AddRefs(homeDir));
   if (NS_SUCCEEDED(rv)) {
     nsCOMPtr<nsIFile> confDir;
 
     for (const auto& dir : extraConfDirs) {
       rv = homeDir->Clone(getter_AddRefs(confDir));
       if (NS_SUCCEEDED(rv)) {
         rv = confDir->AppendNative(nsDependentCString(dir));
         if (NS_SUCCEEDED(rv)) {
@@ -440,22 +422,34 @@ SandboxBrokerPolicyFactory::GetContentPo
   policy->AddPath(rdonly, nsPrintfCString("/proc/%d/statm", aPid).get());
   policy->AddPath(rdonly, nsPrintfCString("/proc/%d/smaps", aPid).get());
 
   // Bug 1384804, notably comment 15
   // Used by libnuma, included by x265/ffmpeg, who falls back
   // to get_mempolicy if this fails
   policy->AddPath(rdonly, nsPrintfCString("/proc/%d/status", aPid).get());
 
+  // Add write permissions on the content process specific temporary dir.
+  nsCOMPtr<nsIFile> tmpDir;
+  nsresult rv = NS_GetSpecialDirectory(NS_APP_CONTENT_PROCESS_TEMP_DIR,
+                                       getter_AddRefs(tmpDir));
+  if (NS_SUCCEEDED(rv)) {
+    nsAutoCString tmpPath;
+    rv = tmpDir->GetNativePath(tmpPath);
+    if (NS_SUCCEEDED(rv)) {
+      policy->AddDir(rdwrcr, tmpPath.get());
+    }
+  }
+
   // userContent.css and the extensions dir sit in the profile, which is
   // normally blocked and we can't get the profile dir earlier in startup,
   // so this must happen here.
   nsCOMPtr<nsIFile> profileDir;
-  nsresult rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR,
-                                       getter_AddRefs(profileDir));
+  rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR,
+                              getter_AddRefs(profileDir));
   if (NS_SUCCEEDED(rv)) {
       nsCOMPtr<nsIFile> workDir;
       rv = profileDir->Clone(getter_AddRefs(workDir));
       if (NS_SUCCEEDED(rv)) {
         rv = workDir->AppendNative(NS_LITERAL_CSTRING("chrome"));
         if (NS_SUCCEEDED(rv)) {
           rv = workDir->AppendNative(NS_LITERAL_CSTRING("userContent.css"));
           if (NS_SUCCEEDED(rv)) {
--- a/security/sandbox/test/browser_content_sandbox_fs.js
+++ b/security/sandbox/test/browser_content_sandbox_fs.js
@@ -148,38 +148,33 @@ function minHomeReadSandboxLevel(level) 
 //
 // Checks that sandboxing is enabled and at the appropriate level
 // setting before triggering tests that do the file I/O.
 //
 // Tests attempting to write to a file in the home directory from the
 // content process--expected to fail.
 //
 // Tests attempting to write to a file in the content temp directory
-// from the content process--expected to succeed. On Mac and Windows,
-// use "ContentTmpD", but on Linux use "TmpD" until Linux uses the
-// content temp dir key.
+// from the content process--expected to succeed. Uses "ContentTmpD".
 //
 // Tests reading various files and directories from file and web
 // content processes.
 //
 add_task(async function() {
   // This test is only relevant in e10s
   if (!gMultiProcessBrowser) {
     ok(false, "e10s is enabled");
     info("e10s is not enabled, exiting");
     return;
   }
 
   let level = 0;
   let prefExists = true;
 
   // Read the security.sandbox.content.level pref.
-  // If the pref isn't set and we're running on Linux on !isNightly(),
-  // exit without failing. The Linux content sandbox is only enabled
-  // on Nightly at this time.
   // eslint-disable-next-line mozilla/use-default-preference-values
   try {
     level = prefs.getIntPref("security.sandbox.content.level");
   } catch (e) {
     prefExists = false;
   }
 
   ok(prefExists, "pref security.sandbox.content.level exists");
@@ -363,25 +358,23 @@ async function testFileAccess() {
       });
     }
   }
 
   // The Linux test runners create the temporary profile in the same
   // system temp dir we give write access to, so this gives a false
   // positive.
   let profileDir = GetProfileDir();
-  if (!isLinux()) {
-    tests.push({
-      desc:     "profile dir",                // description
-      ok:       false,                        // expected to succeed?
-      browser:  webBrowser,                   // browser to run test in
-      file:     profileDir,                   // nsIFile object
-      minLevel: minProfileReadSandboxLevel(), // min level to enable test
-    });
-  }
+  tests.push({
+    desc:     "profile dir",                // description
+    ok:       false,                        // expected to succeed?
+    browser:  webBrowser,                   // browser to run test in
+    file:     profileDir,                   // nsIFile object
+    minLevel: minProfileReadSandboxLevel(), // min level to enable test
+  });
   if (fileContentProcessEnabled) {
     tests.push({
       desc:     "profile dir",
       ok:       true,
       browser:  fileBrowser,
       file:     profileDir,
       minLevel: 0,
     });
@@ -556,27 +549,23 @@ async function testFileAccess() {
       minLevel: 0,
     });
   } else {
     ok(false, `${chromeDir.path} is valid dir`);
   }
 
   let cookiesFile = GetProfileEntry("cookies.sqlite");
   if (cookiesFile.exists() && !cookiesFile.isDirectory()) {
-    // On Linux, the temporary profile used for tests is in the system
-    // temp dir which content has read access to, so this test fails.
-    if (!isLinux()) {
-      tests.push({
-        desc:     "cookies file",
-        ok:       false,
-        browser:  webBrowser,
-        file:     cookiesFile,
-        minLevel: minProfileReadSandboxLevel(),
-      });
-    }
+    tests.push({
+      desc:     "cookies file",
+      ok:       false,
+      browser:  webBrowser,
+      file:     cookiesFile,
+      minLevel: minProfileReadSandboxLevel(),
+    });
     if (fileContentProcessEnabled) {
       tests.push({
         desc:     "cookies file",
         ok:       true,
         browser:  fileBrowser,
         file:     cookiesFile,
         minLevel: 0,
       });
--- a/security/sandbox/test/browser_content_sandbox_utils.js
+++ b/security/sandbox/test/browser_content_sandbox_utils.js
@@ -37,20 +37,16 @@ function fileInHomeDir() {
   homeFile.appendRelativePath(uuid());
   Assert.ok(!homeFile.exists(), homeFile.path + " does not exist");
   return (homeFile);
 }
 
 // Returns a file object for a new file in the content temp dir (.../<UUID>).
 function fileInTempDir() {
   let contentTempKey = "ContentTmpD";
-  if (Services.appinfo.OS == "Linux") {
-    // Linux builds don't use the content-specific temp key
-    contentTempKey = "TmpD";
-  }
 
   // get the content temp dir, make sure it exists
   let ctmp = Services.dirsvc.get(contentTempKey, Ci.nsIFile);
   Assert.ok(ctmp.exists(), "Content temp dir exists");
   Assert.ok(ctmp.isDirectory(), "Content temp dir is a directory");
 
   // build a file object for a new file in content temp
   let tempFile = ctmp.clone();
--- a/toolkit/xre/nsXREDirProvider.cpp
+++ b/toolkit/xre/nsXREDirProvider.cpp
@@ -61,36 +61,34 @@
 #include <ctype.h>
 #endif
 #ifdef XP_IOS
 #include "UIKitDirProvider.h"
 #endif
 
 #if defined(MOZ_CONTENT_SANDBOX)
 #include "mozilla/SandboxSettings.h"
-#if (defined(XP_WIN) || defined(XP_MACOSX))
 #include "nsIUUIDGenerator.h"
 #include "mozilla/Unused.h"
 #if defined(XP_WIN)
 #include "WinUtils.h"
 #endif
 #endif
-#endif
 
 #if defined(XP_MACOSX)
 #define APP_REGISTRY_NAME "Application Registry"
 #elif defined(XP_WIN)
 #define APP_REGISTRY_NAME "registry.dat"
 #else
 #define APP_REGISTRY_NAME "appreg"
 #endif
 
 #define PREF_OVERRIDE_DIRNAME "preferences"
 
-#if (defined(XP_WIN) || defined(XP_MACOSX)) && defined(MOZ_CONTENT_SANDBOX)
+#if defined(MOZ_CONTENT_SANDBOX)
 static already_AddRefed<nsIFile> GetContentProcessSandboxTempDir();
 static nsresult DeleteDirIfExists(nsIFile *dir);
 static bool IsContentSandboxDisabled();
 static const char* GetContentProcessTempBaseDirKey();
 static already_AddRefed<nsIFile> CreateContentProcessSandboxTempDir();
 #endif
 
 nsXREDirProvider* gDirServiceProvider = nullptr;
@@ -494,17 +492,17 @@ nsXREDirProvider::GetFile(const char* aP
   }
   else if (!strcmp(aProperty, XRE_ADDON_APP_DIR)) {
     nsCOMPtr<nsIDirectoryServiceProvider> dirsvc(do_GetService("@mozilla.org/file/directory_service;1", &rv));
     if (NS_FAILED(rv))
       return rv;
     bool unused;
     rv = dirsvc->GetFile("XCurProcD", &unused, getter_AddRefs(file));
   }
-#if (defined(XP_WIN) || defined(XP_MACOSX)) && defined(MOZ_CONTENT_SANDBOX)
+#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)
   else if (NS_SUCCEEDED(GetProfileStartupDir(getter_AddRefs(file)))) {
@@ -654,17 +652,17 @@ nsXREDirProvider::GetFiles(const char* a
 
   rv = NS_NewUnionEnumerator(aResult, appEnum, xreEnum);
   if (NS_FAILED(rv))
     return rv;
 
   return NS_SUCCESS_AGGREGATE_RESULT;
 }
 
-#if (defined(XP_WIN) || defined(XP_MACOSX)) && defined(MOZ_CONTENT_SANDBOX)
+#if defined(MOZ_CONTENT_SANDBOX)
 
 static const char*
 GetContentProcessTempBaseDirKey()
 {
 #if defined(XP_WIN)
   return NS_WIN_LOW_INTEGRITY_TEMP_BASE;
 #else
   return NS_OS_TEMP_DIR;
@@ -776,21 +774,26 @@ CreateContentProcessSandboxTempDir()
     nsID uuid;
     rv = uuidgen->GenerateUUIDInPlace(&uuid);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return nullptr;
     }
 
     char uuidChars[NSID_LENGTH];
     uuid.ToProvidedString(uuidChars);
-    tempDirSuffix.AssignASCII(uuidChars);
+    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::SetCString("security.sandbox.content.tempDirSuffix",
-                                 uuidChars);
+    rv = Preferences::SetString("security.sandbox.content.tempDirSuffix",
+                                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)))) {
@@ -837,18 +840,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(XP_WIN) || defined(XP_MACOSX)) &&
-  // defined(MOZ_CONTENT_SANDBOX)
+#endif // defined(MOZ_CONTENT_SANDBOX)
 
 static const char *const kAppendPrefDir[] = { "defaults", "preferences", nullptr };
 
 #ifdef DEBUG_bsmedberg
 static void
 DumpFileArray(const char *key,
               nsCOMArray<nsIFile> dirs)
 {
@@ -1075,17 +1077,17 @@ nsXREDirProvider::DoStartup()
       }
 
       mozilla::Telemetry::Accumulate(mozilla::Telemetry::NUMBER_OF_PROFILES,
                                      count);
     }
 
     obsSvc->NotifyObservers(nullptr, "profile-initial-state", nullptr);
 
-#if (defined(XP_WIN) || defined(XP_MACOSX)) && defined(MOZ_CONTENT_SANDBOX)
+#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
   }
@@ -1115,17 +1117,17 @@ 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 (defined(XP_WIN) || defined(XP_MACOSX)) && defined(MOZ_CONTENT_SANDBOX)
+#if defined(MOZ_CONTENT_SANDBOX)
   if (XRE_IsParentProcess()) {
     Unused << DeleteDirIfExists(mContentProcessSandboxTempDir);
   }
 #endif
 }
 
 #ifdef XP_WIN
 static nsresult
--- a/toolkit/xre/nsXREDirProvider.h
+++ b/toolkit/xre/nsXREDirProvider.h
@@ -120,17 +120,17 @@ protected:
 
   static nsresult AppendSysUserExtensionPath(nsIFile* aFile);
   static nsresult AppendSysUserExtensionsDevPath(nsIFile* aFile);
 
   // Internal helper that splits a path into components using the '/' and '\\'
   // delimiters.
   static inline nsresult AppendProfileString(nsIFile* aFile, const char* aPath);
 
-#if (defined(XP_WIN) || defined(XP_MACOSX)) && defined(MOZ_CONTENT_SANDBOX)
+#if defined(MOZ_CONTENT_SANDBOX)
   // Load the temp directory for sandboxed content processes
   nsresult LoadContentProcessTempDir();
 #endif
 
   void Append(nsIFile* aDirectory);
 
   nsCOMPtr<nsIDirectoryServiceProvider> mAppProvider;
   // On OSX, mGREDir points to .app/Contents/Resources
@@ -138,16 +138,16 @@ protected:
   // On OSX, mGREBinDir points to .app/Contents/MacOS
   nsCOMPtr<nsIFile>      mGREBinDir;
   // On OSX, mXULAppDir points to .app/Contents/Resources/browser
   nsCOMPtr<nsIFile>      mXULAppDir;
   nsCOMPtr<nsIFile>      mProfileDir;
   nsCOMPtr<nsIFile>      mProfileLocalDir;
   bool                   mProfileNotified;
   bool                   mPrefsInitialized = false;
-#if (defined(XP_WIN) || defined(XP_MACOSX)) && defined(MOZ_CONTENT_SANDBOX)
+#if defined(MOZ_CONTENT_SANDBOX)
   nsCOMPtr<nsIFile>      mContentTempDir;
   nsCOMPtr<nsIFile>      mContentProcessSandboxTempDir;
 #endif
   nsCOMArray<nsIFile>    mAppBundleDirectories;
 };
 
 #endif
--- a/xpcom/io/nsAppDirectoryServiceDefs.h
+++ b/xpcom/io/nsAppDirectoryServiceDefs.h
@@ -76,17 +76,17 @@
 #define NS_APP_SEARCH_50_FILE                   "SrchF"
 
 #define NS_APP_INSTALL_CLEANUP_DIR              "XPIClnupD"  //location of xpicleanup.dat xpicleanup.exe
 
 #define NS_APP_INDEXEDDB_PARENT_DIR             "indexedDBPDir"
 
 #define NS_APP_PERMISSION_PARENT_DIR            "permissionDBPDir"
 
-#if (defined(XP_WIN) || defined(XP_MACOSX)) && defined(MOZ_CONTENT_SANDBOX)
+#if defined(MOZ_CONTENT_SANDBOX)
 //
 // NS_APP_CONTENT_PROCESS_TEMP_DIR refers to a directory that is read and
 // write accessible from a sandboxed content process. The key may be used in
 // either process, but the directory is intended to be used for short-lived
 // files that need to be saved to the filesystem by the content process and
 // don't need to survive browser restarts. The directory is reset on startup.
 // The key is only valid when MOZ_CONTENT_SANDBOX is defined. When
 // MOZ_CONTENT_SANDBOX is defined, the directory the key refers to differs