Backed out 6 changesets (bug 1386404) for failing /webdriver/test/ tests on Linux. r=backout on a CLOSED TREE
authorCsoregi Natalia <ncsoregi@mozilla.com>
Wed, 10 Jan 2018 14:08:51 +0200
changeset 452841 fc577ae44921c821b122c4d290e1fa0fc6899ef6
parent 452840 c0f34f8aaef30708b3354479d24034de58091c48
child 452842 f5b7b31c4da1b539b61d464d7ca8e60039866265
push id1648
push usermtabara@mozilla.com
push dateThu, 01 Mar 2018 12:45:47 +0000
treeherdermozilla-release@cbb9688c2eeb [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbackout
bugs1386404
milestone59.0a1
backs outbe1441859e8bbc6b11b283f736801a58ecb64d3f
8dca7ef74c4a153c95b0577a9dfdadc7b709af57
b7ca6ae185f2eb6e138613d95dfb04ed3a477f1e
2c007d385ce4c1277240945d6f6f0e89a1e3584c
fbe717b9a66443bdefa742be1875fa58de04a309
14f1fbe5263af6decbe78afd47e13030ea6aae5e
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
Backed out 6 changesets (bug 1386404) for failing /webdriver/test/ tests on Linux. r=backout on a CLOSED TREE Backed out changeset be1441859e8b (bug 1386404) Backed out changeset 8dca7ef74c4a (bug 1386404) Backed out changeset b7ca6ae185f2 (bug 1386404) Backed out changeset 2c007d385ce4 (bug 1386404) Backed out changeset fbe717b9a664 (bug 1386404) Backed out changeset 14f1fbe5263a (bug 1386404)
browser/app/profile/firefox.js
ipc/glue/GeckoChildProcessHost.cpp
ipc/glue/GeckoChildProcessHost.h
security/sandbox/linux/broker/SandboxBroker.cpp
security/sandbox/linux/broker/SandboxBroker.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
@@ -1104,22 +1104,24 @@ 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,18 +20,20 @@
 
 #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"
@@ -273,28 +275,16 @@ GeckoChildProcessHost::PrepareLaunch()
 
 #if defined(MOZ_SANDBOX)
   // For other process types we can't rely on them being launched on main
   // thread and they may not have access to prefs in the child process, so allow
   // them to turn on logging via an environment variable.
   mEnableSandboxLogging = mEnableSandboxLogging
                           || !!PR_GetEnv("MOZ_SANDBOX_LOGGING");
 #endif
-#elif defined(XP_LINUX)
-#if defined(MOZ_CONTENT_SANDBOX)
-  // Get and remember the path to the per-content-process tmpdir
-  if (ShouldHaveDirectoryService()) {
-    nsCOMPtr<nsIFile> contentTempDir;
-    nsresult rv = NS_GetSpecialDirectory(NS_APP_CONTENT_PROCESS_TEMP_DIR,
-                                         getter_AddRefs(contentTempDir));
-    if (NS_SUCCEEDED(rv)) {
-      contentTempDir->GetNativePath(mTmpDirName);
-    }
-  }
-#endif
 #endif
 }
 
 #ifdef XP_WIN
 void GeckoChildProcessHost::InitWindowsGroupID()
 {
   // On Win7+, pass the application user model to the child, so it can
   // register with it. This insures windows created by the container
@@ -511,32 +501,16 @@ GeckoChildProcessHost::PerformAsyncLaunc
 
   // `RUST_LOG_CHILD` is meant for logging child processes only.
   nsAutoCString childRustLog(PR_GetEnv("RUST_LOG_CHILD"));
   if (!childRustLog.IsEmpty()) {
     mLaunchOptions->env_map[ENVIRONMENT_LITERAL("RUST_LOG")]
         = ENVIRONMENT_STRING(childRustLog);
   }
 
-#if defined(XP_LINUX) && defined(MOZ_CONTENT_SANDBOX)
-  if (!mTmpDirName.IsEmpty()) {
-    // Point a bunch of things that might want to write from content to our
-    // shiny new content-process specific tmpdir
-    mLaunchOptions->env_map[ENVIRONMENT_LITERAL("TMPDIR")] =
-      ENVIRONMENT_STRING(mTmpDirName);
-    mLaunchOptions->env_map[ENVIRONMENT_LITERAL("XDG_CACHE_HOME")] =
-      ENVIRONMENT_STRING(mTmpDirName);
-    mLaunchOptions->env_map[ENVIRONMENT_LITERAL("XDG_CACHE_DIR")] =
-      ENVIRONMENT_STRING(mTmpDirName);
-    // Partial fix for bug 1380051 (not persistent - should be)
-    mLaunchOptions->env_map[ENVIRONMENT_LITERAL("MESA_GLSL_CACHE_DIR")] =
-      ENVIRONMENT_STRING(mTmpDirName);
-  }
-#endif
-
   return PerformAsyncLaunchInternal(aExtraOpts);
 }
 
 bool
 GeckoChildProcessHost::RunPerformAsyncLaunch(std::vector<std::string> aExtraOpts)
 {
   InitializeChannel();
 
--- a/ipc/glue/GeckoChildProcessHost.h
+++ b/ipc/glue/GeckoChildProcessHost.h
@@ -188,21 +188,16 @@ private:
   // 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.
   std::queue<IPC::Message> mQueue;
 
-  // Set this up before we're called from a different thread.
-#if defined(OS_LINUX)
-  nsCString mTmpDirName;
-#endif
-
   static uint32_t sNextUniqueID;
 
   static bool sRunSelfAsContentProc;
 
 #if defined(MOZ_WIDGET_ANDROID)
   void LaunchAndroidService(const char* type,
                             const std::vector<std::string>& argv,
                             const base::file_handle_mapping_vector& fds_to_remap,
--- a/security/sandbox/linux/broker/SandboxBroker.cpp
+++ b/security/sandbox/linux/broker/SandboxBroker.cpp
@@ -23,19 +23,16 @@
 
 #include "base/string_util.h"
 #include "mozilla/Assertions.h"
 #include "mozilla/DebugOnly.h"
 #include "mozilla/Move.h"
 #include "mozilla/NullPtr.h"
 #include "mozilla/Sprintf.h"
 #include "mozilla/ipc/FileDescriptor.h"
-#include "nsDirectoryServiceDefs.h"
-#include "nsAppDirectoryServiceDefs.h"
-#include "SpecialSystemDirectory.h"
 #include "sandbox/linux/system_headers/linux_syscalls.h"
 
 namespace mozilla {
 
 // This constructor signals failure by setting mFileDesc and aClientFd to -1.
 SandboxBroker::SandboxBroker(UniquePtr<const Policy> aPolicy, int aChildPid,
                              int& aClientFd)
   : mChildPid(aChildPid), mPolicy(Move(aPolicy))
@@ -513,44 +510,16 @@ SandboxBroker::ConvertToRealPath(char* a
       // Size changed, but guaranteed to be 0 terminated
       aPathLen = strlen(aPath);
     }
     // ValidatePath will handle failure to translate
   }
   return aPathLen;
 }
 
-size_t
-SandboxBroker::RemapTempDirs(char* aPath, size_t aBufSize, size_t aPathLen)
-{
-  nsAutoCString path(aPath);
-  static const nsLiteralCString tempPrefix(NS_LITERAL_CSTRING("/tmp"));
-
-  if (StringBeginsWith(path, tempPrefix)) {
-    size_t prefixLen = tempPrefix.Length();
-    const nsDependentCSubstring cutPath =
-      Substring(path, prefixLen, path.Length() - prefixLen);
-    // Only now try to get the content process temp 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)) {
-        tmpPath.Append(cutPath);
-        base::strlcpy(aPath, tmpPath.get(), aBufSize);
-        return strlen(aPath);
-      }
-    }
-  }
-
-  return aPathLen;
-}
-
 nsCString
 SandboxBroker::ReverseSymlinks(const nsACString& aPath)
 {
   // Revert any symlinks we previously resolved.
   int32_t cutLength = aPath.Length();
   nsCString cutPath(Substring(aPath, 0, cutLength));
 
   for (;;) {
@@ -704,29 +673,24 @@ SandboxBroker::ThreadMain(void)
       // First string is guaranteed to be 0-terminated.
       pathLen = first_len;
 
       // Look up the first pathname but first translate relative paths.
       pathLen = ConvertToRealPath(pathBuf, sizeof(pathBuf), pathLen);
       perms = mPolicy->Lookup(nsDependentCString(pathBuf, pathLen));
 
       // We don't have read permissions on the requested dir.
+      // Did we arrive from a symlink in a path that is not writable?
+      // Then try to figure out the original path and see if that is readable.
       if (!(perms & MAY_READ)) {
-          // Was it a tempdir that we can remap?
-          pathLen = RemapTempDirs(pathBuf, sizeof(pathBuf), pathLen);
-          perms = mPolicy->Lookup(nsDependentCString(pathBuf, pathLen));
-          if (!(perms & MAY_READ)) {
-            // Did we arrive from a symlink in a path that is not writable?
-            // Then try to figure out the original path and see if that is
-            // readable. Work on the original path, this reverses
-            // ConvertToRealPath above.
-            int symlinkPerms = SymlinkPermissions(recvBuf, first_len);
-            if (symlinkPerms > 0) {
-              perms = symlinkPerms;
-            }
+          // Work on the original path,
+          // this reverses ConvertToRealPath above.
+          int symlinkPerms = SymlinkPermissions(recvBuf, first_len);
+          if (symlinkPerms > 0) {
+            perms = symlinkPerms;
           }
       }
 
       // Same for the second path.
       pathLen2 = strnlen(pathBuf2, kMaxPathLen);
       if (pathLen2 > 0) {
         // Force 0 termination.
         pathBuf2[pathLen2] = '\0';
--- a/security/sandbox/linux/broker/SandboxBroker.h
+++ b/security/sandbox/linux/broker/SandboxBroker.h
@@ -138,18 +138,16 @@ class SandboxBroker final
 
   SandboxBroker(UniquePtr<const Policy> aPolicy, int aChildPid,
                 int& aClientFd);
   void ThreadMain(void) override;
   void AuditPermissive(int aOp, int aFlags, int aPerms, const char* aPath);
   void AuditDenial(int aOp, int aFlags, int aPerms, const char* aPath);
   // Remap relative paths to absolute paths.
   size_t ConvertToRealPath(char* aPath, size_t aBufSize, size_t aPathLen);
-  // Remap references to /tmp and friends to the content process tempdir
-  size_t RemapTempDirs(char* aPath, size_t aBufSize, size_t aPathLen);
   nsCString ReverseSymlinks(const nsACString& aPath);
   // Retrieves permissions for the path the original symlink sits in.
   int SymlinkPermissions(const char* aPath, const size_t aPathLen);
   // In SandboxBrokerRealPath.cpp
   char* SymlinkPath(const Policy* aPolicy, const char* __restrict aPath,
                     char* __restrict aResolved, int* aPermission);
 
   // Holding a UniquePtr should disallow copying, but to make that explicit:
--- a/security/sandbox/linux/broker/SandboxBrokerPolicyFactory.cpp
+++ b/security/sandbox/linux/broker/SandboxBrokerPolicyFactory.cpp
@@ -183,16 +183,35 @@ 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
@@ -228,16 +247,18 @@ SandboxBrokerPolicyFactory::SandboxBroke
   policy->AddDir(rdonly, "/usr/lib32");
   policy->AddDir(rdonly, "/usr/lib64");
   policy->AddDir(rdonly, "/etc");
 #ifdef MOZ_PULSEAUDIO
   policy->AddPath(rdonly, "/var/lib/dbus/machine-id");
 #endif
   policy->AddDir(rdonly, "/usr/share");
   policy->AddDir(rdonly, "/usr/local/share");
+  policy->AddDir(rdonly, "/usr/tmp");
+  policy->AddDir(rdonly, "/var/tmp");
   // Various places where fonts reside
   policy->AddDir(rdonly, "/usr/X11R6/lib/X11/fonts");
   policy->AddDir(rdonly, "/nix/store");
   policy->AddDir(rdonly, "/run/host/fonts");
   policy->AddDir(rdonly, "/run/host/user-fonts");
 
   AddMesaSysfsPaths(policy);
   AddLdconfigPaths(policy);
@@ -282,18 +303,17 @@ SandboxBrokerPolicyFactory::SandboxBroke
   // access to.
   mozilla::Array<const char*, 3> extraConfDirs = {
     ".config",   // Fallback if XDG_CONFIG_PATH isn't set
     ".themes",
     ".fonts",
   };
 
   nsCOMPtr<nsIFile> homeDir;
-  nsresult rv = GetSpecialSystemDirectory(Unix_HomeDirectory,
-                                          getter_AddRefs(homeDir));
+  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)) {
@@ -381,32 +401,16 @@ SandboxBrokerPolicyFactory::SandboxBroke
     // Therefore in non-release builds we allow reads from the whole repository.
     // MOZ_DEVELOPER_REPO_DIR is set by mach run.
     const char *developer_repo_dir = PR_GetEnv("MOZ_DEVELOPER_REPO_DIR");
     if (developer_repo_dir) {
       policy->AddDir(rdonly, developer_repo_dir);
     }
   }
 
-#ifdef DEBUG
-  char *bloatLog = PR_GetEnv("XPCOM_MEM_BLOAT_LOG");
-  // XPCOM_MEM_BLOAT_LOG has the format
-  // /tmp/tmpd0YzFZ.mozrunner/runtests_leaks.log
-  // but stores into /tmp/tmpd0YzFZ.mozrunner/runtests_leaks_tab_pid3411.log
-  // So cut the .log part and whitelist the prefix.
-  if (bloatLog != nullptr) {
-    size_t bloatLen = strlen(bloatLog);
-    if (bloatLen >= 4) {
-      nsAutoCString bloatStr(bloatLog);
-      bloatStr.Truncate(bloatLen - 4);
-      policy->AddPrefix(rdwrcr, bloatStr.get());
-    }
-  }
-#endif
-
   mCommonContentPolicy.reset(policy);
 #endif
 }
 
 #ifdef MOZ_CONTENT_SANDBOX
 UniquePtr<SandboxBroker::Policy>
 SandboxBrokerPolicyFactory::GetContentPolicy(int aPid, bool aFileProcess)
 {
@@ -454,44 +458,35 @@ 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;
-  rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR,
-                              getter_AddRefs(profileDir));
+  nsresult 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)) {
-          nsAutoCString tmpPath;
-          rv = workDir->GetNativePath(tmpPath);
+          rv = workDir->AppendNative(NS_LITERAL_CSTRING("userContent.css"));
           if (NS_SUCCEEDED(rv)) {
-            policy->AddDir(rdonly, tmpPath.get());
+            nsAutoCString tmpPath;
+            rv = workDir->GetNativePath(tmpPath);
+            if (NS_SUCCEEDED(rv)) {
+              policy->AddPath(rdonly, tmpPath.get());
+            }
           }
         }
       }
       rv = profileDir->Clone(getter_AddRefs(workDir));
       if (NS_SUCCEEDED(rv)) {
         rv = workDir->AppendNative(NS_LITERAL_CSTRING("extensions"));
         if (NS_SUCCEEDED(rv)) {
           nsAutoCString tmpPath;
--- a/security/sandbox/test/browser_content_sandbox_fs.js
+++ b/security/sandbox/test/browser_content_sandbox_fs.js
@@ -158,33 +158,38 @@ 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. Uses "ContentTmpD".
+// 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.
 //
 // 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 = Services.prefs.getIntPref("security.sandbox.content.level");
   } catch (e) {
     prefExists = false;
   }
 
   ok(prefExists, "pref security.sandbox.content.level exists");
@@ -366,25 +371,30 @@ async function testFileAccess() {
         browser:  webBrowser,                   // browser to run test in
         file:     fontFile,                     // nsIFile object
         minLevel: minHomeReadSandboxLevel(),    // min level to enable test
         func:     readFile,                     // the test function to use
       });
     }
   }
 
+  // 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();
-  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
-    func:     readDir,
-  });
+  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
+      func:     readDir,
+    });
+  }
   if (fileContentProcessEnabled) {
     tests.push({
       desc:     "profile dir",
       ok:       true,
       browser:  fileBrowser,
       file:     profileDir,
       minLevel: 0,
       func:     readDir,
@@ -636,24 +646,28 @@ async function testFileAccess() {
       func:     readDir,
     });
   } else {
     ok(false, `${chromeDir.path} is valid dir`);
   }
 
   let cookiesFile = GetProfileEntry("cookies.sqlite");
   if (cookiesFile.exists() && !cookiesFile.isDirectory()) {
-    tests.push({
-      desc:     "cookies file",
-      ok:       false,
-      browser:  webBrowser,
-      file:     cookiesFile,
-      minLevel: minProfileReadSandboxLevel(),
-      func:     readFile,
-    });
+    // 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(),
+        func:     readFile,
+      });
+    }
     if (fileContentProcessEnabled) {
       tests.push({
         desc:     "cookies file",
         ok:       true,
         browser:  fileBrowser,
         file:     cookiesFile,
         minLevel: 0,
         func:     readFile,
--- a/security/sandbox/test/browser_content_sandbox_utils.js
+++ b/security/sandbox/test/browser_content_sandbox_utils.js
@@ -36,16 +36,20 @@ 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,34 +61,36 @@
 #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(MOZ_CONTENT_SANDBOX)
+#if (defined(XP_WIN) || defined(XP_MACOSX)) && 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;
@@ -492,17 +494,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(MOZ_CONTENT_SANDBOX)
+#if (defined(XP_WIN) || defined(XP_MACOSX)) && 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)))) {
@@ -652,17 +654,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(MOZ_CONTENT_SANDBOX)
+#if (defined(XP_WIN) || defined(XP_MACOSX)) && 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;
@@ -774,26 +776,21 @@ 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, NSID_LENGTH);
-#ifdef XP_UNIX
-    // Braces in a path are somewhat annoying to deal with
-    // and pretty alien on Unix
-    tempDirSuffix.StripChars(u"{}");
-#endif
+    tempDirSuffix.AssignASCII(uuidChars);
 
     // Save the pref
-    rv = Preferences::SetString("security.sandbox.content.tempDirSuffix",
-                                tempDirSuffix);
+    rv = Preferences::SetCString("security.sandbox.content.tempDirSuffix",
+                                 uuidChars);
     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)))) {
@@ -840,17 +837,18 @@ 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(XP_WIN) || defined(XP_MACOSX)) &&
+  // defined(MOZ_CONTENT_SANDBOX)
 
 static const char *const kAppendPrefDir[] = { "defaults", "preferences", nullptr };
 
 #ifdef DEBUG_bsmedberg
 static void
 DumpFileArray(const char *key,
               nsCOMArray<nsIFile> dirs)
 {
@@ -1058,17 +1056,17 @@ nsXREDirProvider::DoStartup()
       }
 
       mozilla::Telemetry::Accumulate(mozilla::Telemetry::NUMBER_OF_PROFILES,
                                      count);
     }
 
     obsSvc->NotifyObservers(nullptr, "profile-initial-state", nullptr);
 
-#if defined(MOZ_CONTENT_SANDBOX)
+#if (defined(XP_WIN) || defined(XP_MACOSX)) && 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
   }
@@ -1098,17 +1096,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(MOZ_CONTENT_SANDBOX)
+#if (defined(XP_WIN) || defined(XP_MACOSX)) && 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(MOZ_CONTENT_SANDBOX)
+#if (defined(XP_WIN) || defined(XP_MACOSX)) && 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(MOZ_CONTENT_SANDBOX)
+#if (defined(XP_WIN) || defined(XP_MACOSX)) && 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
@@ -71,17 +71,17 @@
 #define NS_APP_CACHE_PARENT_DIR                 "cachePDir"
 
 #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(MOZ_CONTENT_SANDBOX)
+#if (defined(XP_WIN) || defined(XP_MACOSX)) && 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