Bug 1236108: Modify sandbox initialization code to use directory service to obtain content process temp directory; r=bobowen,haik a=lizzard
authorAaron Klotz <aklotz@mozilla.com>
Tue, 08 Mar 2016 11:02:27 -0800
changeset 317635 a25c8fb1caa739a8aafa9f583f63d31e1ad275b8
parent 317634 728faac43cb5e542c4d879bfb0e8ea1ac0495759
child 317636 1584c57bea14602d8f36c2b778f5b0fcae7d2fac
push id5819
push useraklotz@mozilla.com
push dateMon, 28 Mar 2016 18:29:30 +0000
treeherdermozilla-beta@0ca97166862b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbobowen, haik, lizzard
bugs1236108
milestone46.0
Bug 1236108: Modify sandbox initialization code to use directory service to obtain content process temp directory; r=bobowen,haik a=lizzard The previous patch in this series creates a new directory service entry specifically for obtaining the content process temp directory. This patch converts everything else to reference that entry. It also sets appropriate environment variables in the content processes so that system APIs automatically pick up the directory. This is necessary for the crash reporter to be able to call those APIs in exception handling contexts. MozReview-Commit-ID: DF6aNKrWnWp
dom/ipc/ContentProcess.cpp
toolkit/xre/nsAppRunner.cpp
--- a/dom/ipc/ContentProcess.cpp
+++ b/dom/ipc/ContentProcess.cpp
@@ -4,70 +4,112 @@
  * 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/ipc/IOThreadChild.h"
 
 #include "ContentProcess.h"
 
 #if defined(XP_WIN) && defined(MOZ_CONTENT_SANDBOX)
+#include "mozilla/WindowsVersion.h"
+#endif
+
+#if defined(XP_MACOSX) && defined(MOZ_CONTENT_SANDBOX)
+#include <stdlib.h>
+#endif
+
+#if (defined(XP_WIN) || defined(XP_MACOSX)) && defined(MOZ_CONTENT_SANDBOX)
 #include "mozilla/Preferences.h"
-#include "mozilla/WindowsVersion.h"
+#include "nsAppDirectoryServiceDefs.h"
 #include "nsDirectoryService.h"
 #include "nsDirectoryServiceDefs.h"
 #endif
 
 using mozilla::ipc::IOThreadChild;
 
 namespace mozilla {
 namespace dom {
 
 #if defined(XP_WIN) && defined(MOZ_CONTENT_SANDBOX)
+static bool
+IsSandboxTempDirRequired()
+{
+  // On Windows, a sandbox-writable temp directory is only used
+  // for Vista or later with sandbox pref level >= 1.
+  return (IsVistaOrLater() &&
+    (Preferences::GetInt("security.sandbox.content.level") >= 1));
+}
+
+static void
+SetTmpEnvironmentVariable(nsIFile* aValue)
+{
+  // 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.
+  nsAutoString fullTmpPath;
+  nsresult rv = aValue->GetPath(fullTmpPath);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return;
+  }
+  NS_WARN_IF(!SetEnvironmentVariableW(L"TMP", fullTmpPath.get()));
+  // We also set TEMP in case there is naughty third-party code that is
+  // referencing the environment variable directly.
+  NS_WARN_IF(!SetEnvironmentVariableW(L"TEMP", fullTmpPath.get()));
+}
+#endif
+
+#if defined(XP_MACOSX) && defined(MOZ_CONTENT_SANDBOX)
+static bool
+IsSandboxTempDirRequired()
+{
+  // On OSX, use the sandbox-writable temp when the pref level >= 1.
+  return (Preferences::GetInt("security.sandbox.content.level") >= 1);
+}
+
+static void
+SetTmpEnvironmentVariable(nsIFile* aValue)
+{
+  nsAutoCString fullTmpPath;
+  nsresult rv = aValue->GetNativePath(fullTmpPath);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return;
+  }
+  NS_WARN_IF(setenv("TMPDIR", fullTmpPath.get(), 1) != 0);
+}
+#endif
+
+#if (defined(XP_WIN) || defined(XP_MACOSX)) && defined(MOZ_CONTENT_SANDBOX)
 static void
 SetUpSandboxEnvironment()
 {
   MOZ_ASSERT(nsDirectoryService::gService,
     "SetUpSandboxEnvironment relies on nsDirectoryService being initialized");
 
-  // A low integrity temp only currently makes sense for Vista or Later and
-  // sandbox pref level >= 1.
-  if (!IsVistaOrLater() ||
-      Preferences::GetInt("security.sandbox.content.level") < 1) {
+  if (!IsSandboxTempDirRequired()) {
     return;
   }
 
-  nsAdoptingString tempDirSuffix =
-    Preferences::GetString("security.sandbox.content.tempDirSuffix");
-  if (tempDirSuffix.IsEmpty()) {
-    NS_WARNING("Low integrity temp suffix pref not set.");
-    return;
-  }
-
-  // Get the base low integrity Mozilla temp directory.
-  nsCOMPtr<nsIFile> lowIntegrityTemp;
-  nsresult rv = nsDirectoryService::gService->Get(NS_WIN_LOW_INTEGRITY_TEMP_BASE,
-                                                  NS_GET_IID(nsIFile),
-                                                  getter_AddRefs(lowIntegrityTemp));
+  nsCOMPtr<nsIFile> sandboxedContentTemp;
+  nsresult rv =
+    nsDirectoryService::gService->Get(NS_APP_CONTENT_PROCESS_TEMP_DIR,
+                                      NS_GET_IID(nsIFile),
+                                      getter_AddRefs(sandboxedContentTemp));
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return;
   }
 
-  // Append our profile specific temp name.
-  rv = lowIntegrityTemp->Append(NS_LITERAL_STRING("Temp-") + tempDirSuffix);
+  // Change the gecko defined temp directory to our sandbox-writable one.
+  // Undefine returns a failure if the property is not already set.
+  Unused << nsDirectoryService::gService->Undefine(NS_OS_TEMP_DIR);
+  rv = nsDirectoryService::gService->Set(NS_OS_TEMP_DIR, sandboxedContentTemp);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return;
   }
 
-  // Change the gecko defined temp directory to our low integrity one.
-  // Undefine returns a failure if the property is not already set.
-  Unused << nsDirectoryService::gService->Undefine(NS_OS_TEMP_DIR);
-  rv = nsDirectoryService::gService->Set(NS_OS_TEMP_DIR, lowIntegrityTemp);
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    return;
-  }
+  SetTmpEnvironmentVariable(sandboxedContentTemp);
 }
 #endif
 
 void
 ContentProcess::SetAppDir(const nsACString& aPath)
 {
   mXREEmbed.SetAppDir(aPath);
 }
@@ -77,20 +119,20 @@ ContentProcess::Init()
 {
     mContent.Init(IOThreadChild::message_loop(),
                   ParentPid(),
                   IOThreadChild::channel());
     mXREEmbed.Start();
     mContent.InitXPCOM();
     mContent.InitGraphicsDeviceData();
 
-#if defined(XP_WIN) && defined(MOZ_CONTENT_SANDBOX)
+#if (defined(XP_WIN) || defined(XP_MACOSX)) && defined(MOZ_CONTENT_SANDBOX)
     SetUpSandboxEnvironment();
 #endif
-    
+
     return true;
 }
 
 // Note: CleanUp() never gets called in non-debug builds because we exit early
 // in ContentChild::ActorDestroy().
 void
 ContentProcess::CleanUp()
 {
--- a/toolkit/xre/nsAppRunner.cpp
+++ b/toolkit/xre/nsAppRunner.cpp
@@ -591,53 +591,65 @@ ProcessDDE(nsINativeAppSupport* aNative,
  * @return true in all environments
 */
 static bool
 CanShowProfileManager()
 {
   return true;
 }
 
-#if defined(XP_WIN) && defined(MOZ_CONTENT_SANDBOX)
+#if (defined(XP_WIN) || defined(XP_MACOSX)) && defined(MOZ_CONTENT_SANDBOX)
 static already_AddRefed<nsIFile>
-GetAndCleanLowIntegrityTemp(const nsAString& aTempDirSuffix)
+GetAndCleanTempDir()
 {
-  // Get the base low integrity Mozilla temp directory.
-  nsCOMPtr<nsIFile> lowIntegrityTemp;
-  nsresult rv = NS_GetSpecialDirectory(NS_WIN_LOW_INTEGRITY_TEMP_BASE,
-                                       getter_AddRefs(lowIntegrityTemp));
+  // Get the directory within which we'll place the
+  // sandbox-writable temp directory
+  nsCOMPtr<nsIFile> tempDir;
+  nsresult rv = NS_GetSpecialDirectory(NS_APP_CONTENT_PROCESS_TEMP_DIR,
+                                       getter_AddRefs(tempDir));
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return nullptr;
   }
 
-  // Append our profile specific temp name.
-  rv = lowIntegrityTemp->Append(NS_LITERAL_STRING("Temp-") + aTempDirSuffix);
-  if (NS_WARN_IF(NS_FAILED(rv))) {
+  rv = tempDir->Remove(/* aRecursive */ true);
+  if (NS_FAILED(rv) && rv != NS_ERROR_FILE_NOT_FOUND) {
+    NS_WARNING("Failed to delete temp directory.");
     return nullptr;
   }
 
-  rv = lowIntegrityTemp->Remove(/* aRecursive */ true);
-  if (NS_FAILED(rv) && rv != NS_ERROR_FILE_NOT_FOUND) {
-    NS_WARNING("Failed to delete low integrity temp directory.");
-    return nullptr;
-  }
-
-  return lowIntegrityTemp.forget();
+  return tempDir.forget();
 }
 
 static void
 SetUpSandboxEnvironment()
 {
-  // A low integrity temp only currently makes sense for Vista and later, e10s
-  // and sandbox pref level >= 1.
-  if (!IsVistaOrLater() || !BrowserTabsRemoteAutostart() ||
-      Preferences::GetInt("security.sandbox.content.level") < 1) {
+  // Setup a sandbox-writable temp directory. i.e., a directory
+  // that is writable by a sandboxed content process. This
+  // only applies when e10s is enabled, depending on the platform
+  // and setting of security.sandbox.content.level.
+  if (!BrowserTabsRemoteAutostart()) {
     return;
   }
 
+#if defined(XP_WIN)
+  // For Windows, the temp dir only makes sense for Vista and later
+  // with a sandbox pref level >= 1
+  if (!IsVistaOrLater() ||
+      (Preferences::GetInt("security.sandbox.content.level") < 1)) {
+    return;
+  }
+#endif
+
+#if defined(XP_MACOSX)
+  // For OSX, we just require sandbox pref level >= 1.
+  if (Preferences::GetInt("security.sandbox.content.level") < 1) {
+    return;
+  }
+#endif
+
   // Get (and create if blank) temp directory suffix pref.
   nsresult rv;
   nsAdoptingString tempDirSuffix =
     Preferences::GetString("security.sandbox.content.tempDirSuffix");
   if (tempDirSuffix.IsEmpty()) {
     nsCOMPtr<nsIUUIDGenerator> uuidgen =
       do_GetService("@mozilla.org/uuid-generator;1", &rv);
     if (NS_WARN_IF(NS_FAILED(rv))) {
@@ -667,24 +679,24 @@ SetUpSandboxEnvironment()
     if (!prefsvc || NS_FAILED(prefsvc->SavePrefFile(nullptr))) {
       // Again, if we fail to save the pref file we might not be able to clean
       // up the temp directory, so don't create one.
       NS_WARNING("Failed to save pref file, cannot create temp dir.");
       return;
     }
   }
 
-  // Get (and clean up if still there) the low integrity Mozilla temp directory.
-  nsCOMPtr<nsIFile> lowIntegrityTemp = GetAndCleanLowIntegrityTemp(tempDirSuffix);
-  if (!lowIntegrityTemp) {
-    NS_WARNING("Failed to get or clean low integrity Mozilla temp directory.");
+  // Get (and clean up if still there) the sandbox-writable temp directory.
+  nsCOMPtr<nsIFile> tempDir = GetAndCleanTempDir();
+  if (!tempDir) {
+    NS_WARNING("Failed to get or clean sandboxed temp directory.");
     return;
   }
 
-  rv = lowIntegrityTemp->Create(nsIFile::DIRECTORY_TYPE, 0700);
+  rv = tempDir->Create(nsIFile::DIRECTORY_TYPE, 0700);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return;
   }
 }
 
 #if defined(NIGHTLY_BUILD)
 static void
 CleanUpOldSandboxEnvironment()
@@ -728,35 +740,30 @@ CleanUpOldSandboxEnvironment()
     }
   }
 }
 #endif
 
 static void
 CleanUpSandboxEnvironment()
 {
+#if defined(XP_WIN)
   // We can't have created a low integrity temp before Vista.
   if (!IsVistaOrLater()) {
     return;
   }
+#endif
 
 #if defined(NIGHTLY_BUILD)
   CleanUpOldSandboxEnvironment();
 #endif
 
-  // Get temp directory suffix pref.
-  nsAdoptingString tempDirSuffix =
-    Preferences::GetString("security.sandbox.content.tempDirSuffix");
-  if (tempDirSuffix.IsEmpty()) {
-    return;
-  }
-
   // Get and remove the low integrity Mozilla temp directory.
   // This function already warns if the deletion fails.
-  nsCOMPtr<nsIFile> lowIntegrityTemp = GetAndCleanLowIntegrityTemp(tempDirSuffix);
+  nsCOMPtr<nsIFile> tempDir = GetAndCleanTempDir();
 }
 #endif
 
 bool gSafeMode = false;
 
 /**
  * The nsXULAppInfo object implements nsIFactory so that it can be its own
  * singleton.