Bug 1162327 Part 1: Change low integrity temp to a fixed dir per profile and improve clean-up. r=jimm, r=froydnj
authorBob Owen <bobowencode@gmail.com>
Mon, 18 May 2015 11:51:07 +0100
changeset 265180 116d87a1a2a8e405fd93992dbe7aedaed82aa0f7
parent 265179 6800629ce1b1bf46220a6b215631869935750545
child 265181 ca9f095bb18cd0318938b7ebc634f27bba21a1dd
push id2102
push usermartin.thomson@gmail.com
push dateMon, 18 May 2015 17:35:37 +0000
reviewersjimm, froydnj
bugs1162327
milestone41.0a1
Bug 1162327 Part 1: Change low integrity temp to a fixed dir per profile and improve clean-up. r=jimm, r=froydnj
browser/app/profile/firefox.js
dom/ipc/ContentProcess.cpp
toolkit/xre/nsAppRunner.cpp
xpcom/io/nsDirectoryService.cpp
xpcom/io/nsDirectoryServiceAtomList.h
xpcom/io/nsDirectoryServiceDefs.h
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -1205,16 +1205,19 @@ pref("dom.ipc.plugins.sandbox-level.defa
 // 2 - a policy that we can reasonably call an effective sandbox
 // 3 - an equivalent basic policy to the Chromium renderer processes
 #if defined(NIGHTLY_BUILD)
 pref("security.sandbox.content.level", 1);
 #else
 pref("security.sandbox.content.level", 0);
 #endif
 
+// ID (a UUID when set by gecko) that is used as a per profile suffix to a low
+// integrity temp directory.
+pref("security.sandbox.content.tempDirSuffix", "");
 
 #if defined(MOZ_STACKWALKING)
 // This controls the depth of stack trace that is logged when Windows sandbox
 // logging is turned on.  This is only currently available for the content
 // process because the only other sandbox (for GMP) has too strict a policy to
 // allow stack tracing.  This does not require a restart to take effect.
 pref("security.sandbox.windows.log.stackTraceDepth", 0);
 #endif
--- a/dom/ipc/ContentProcess.cpp
+++ b/dom/ipc/ContentProcess.cpp
@@ -5,92 +5,69 @@
  * 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/Preferences.h"
+#include "mozilla/WindowsVersion.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 already_AddRefed<nsIFile>
-GetLowIntegrityTemp()
-{
-  MOZ_ASSERT(nsDirectoryService::gService,
-    "GetLowIntegrityTemp relies on nsDirectoryService being initialized");
-
-  // A low integrity temp only currently makes sense for sandbox pref level 1.
-  if (Preferences::GetInt("security.sandbox.content.level") != 1) {
-    return nullptr;
-  }
-
-  nsCOMPtr<nsIFile> lowIntegrityTemp;
-  nsresult rv = nsDirectoryService::gService->Get(NS_WIN_LOW_INTEGRITY_TEMP,
-                                                  NS_GET_IID(nsIFile),
-                                                  getter_AddRefs(lowIntegrityTemp));
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    return nullptr;
-  }
-
-  return lowIntegrityTemp.forget();
-}
-
 static void
 SetUpSandboxEnvironment()
 {
   MOZ_ASSERT(nsDirectoryService::gService,
     "SetUpSandboxEnvironment relies on nsDirectoryService being initialized");
 
-  // Setup to use a low integrity temp if available.
-  nsCOMPtr<nsIFile> lowIntegrityTemp = GetLowIntegrityTemp();
-  if (!lowIntegrityTemp) {
+  // 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) {
     return;
   }
 
-  // Undefine returns a failure if the property is not already set.
-  unused << nsDirectoryService::gService->Undefine(NS_OS_TEMP_DIR);
-  nsresult rv = nsDirectoryService::gService->Set(NS_OS_TEMP_DIR, lowIntegrityTemp);
+  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));
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return;
   }
 
-  // Set TEMP and TMP environment variables.
-  nsAutoString lowIntegrityTempPath;
-  rv = lowIntegrityTemp->GetPath(lowIntegrityTempPath);
+  // Append our profile specific temp name.
+  rv = lowIntegrityTemp->Append(NS_LITERAL_STRING("Temp-") + tempDirSuffix);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return;
   }
 
-  bool setOK = SetEnvironmentVariableW(L"TEMP", lowIntegrityTempPath.get());
-  NS_WARN_IF_FALSE(setOK, "Failed to set TEMP to low integrity temp path");
-  setOK = SetEnvironmentVariableW(L"TMP", lowIntegrityTempPath.get());
-  NS_WARN_IF_FALSE(setOK, "Failed to set TMP to low integrity temp path");
-}
-
-static void
-CleanUpSandboxEnvironment()
-{
-  // Remove low integrity temp if it exists.
-  nsCOMPtr<nsIFile> lowIntegrityTemp = GetLowIntegrityTemp();
-  if (!lowIntegrityTemp) {
+  // 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;
   }
-
-  // Don't check the return value as the directory will only have been created
-  // if it has been used.
-  unused << lowIntegrityTemp->Remove(/* aRecursive */ true);
 }
 #endif
 
 void
 ContentProcess::SetAppDir(const nsACString& aPath)
 {
   mXREEmbed.SetAppDir(aPath);
 }
@@ -109,16 +86,13 @@ ContentProcess::Init()
 #endif
     
     return true;
 }
 
 void
 ContentProcess::CleanUp()
 {
-#if defined(XP_WIN) && defined(MOZ_CONTENT_SANDBOX)
-    CleanUpSandboxEnvironment();
-#endif
     mXREEmbed.Stop();
 }
 
 } // namespace dom
 } // namespace mozilla
--- a/toolkit/xre/nsAppRunner.cpp
+++ b/toolkit/xre/nsAppRunner.cpp
@@ -98,16 +98,20 @@
 #include <intrin.h>
 #include <math.h>
 #include "cairo/cairo-features.h"
 #include "mozilla/WindowsVersion.h"
 
 #ifndef PROCESS_DEP_ENABLE
 #define PROCESS_DEP_ENABLE 0x1
 #endif
+
+#if defined(MOZ_CONTENT_SANDBOX)
+#include "nsIUUIDGenerator.h"
+#endif
 #endif
 
 #ifdef ACCESSIBILITY
 #include "nsAccessibilityService.h"
 #if defined(XP_WIN)
 #include "mozilla/a11y/Compatibility.h"
 #endif
 #endif
@@ -578,16 +582,126 @@ ProcessDDE(nsINativeAppSupport* aNative,
  * @return true in all environments
 */
 static bool
 CanShowProfileManager()
 {
   return true;
 }
 
+#if defined(XP_WIN) && defined(MOZ_CONTENT_SANDBOX)
+static already_AddRefed<nsIFile>
+GetAndCleanLowIntegrityTemp(const nsAString& aTempDirSuffix)
+{
+  // Get the base low integrity Mozilla temp directory.
+  nsCOMPtr<nsIFile> lowIntegrityTemp;
+  nsresult rv = NS_GetSpecialDirectory(NS_WIN_LOW_INTEGRITY_TEMP_BASE,
+                                       getter_AddRefs(lowIntegrityTemp));
+  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))) {
+    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();
+}
+
+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) {
+    return;
+  }
+
+  // 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))) {
+      return;
+    }
+
+    nsID uuid;
+    rv = uuidgen->GenerateUUIDInPlace(&uuid);
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return;
+    }
+
+    char uuidChars[NSID_LENGTH];
+    uuid.ToProvidedString(uuidChars);
+    tempDirSuffix.AssignASCII(uuidChars);
+
+    // Save the pref to be picked up later.
+    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;
+    }
+
+    nsCOMPtr<nsIPrefService> prefsvc = Preferences::GetService();
+    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.");
+    return;
+  }
+
+  rv = lowIntegrityTemp->Create(nsIFile::DIRECTORY_TYPE, 0700);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return;
+  }
+}
+
+static void
+CleanUpSandboxEnvironment()
+{
+  // We can't have created a low integrity temp before Vista.
+  if (!IsVistaOrLater()) {
+    return;
+  }
+
+  // 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.
+  unused << GetAndCleanLowIntegrityTemp(tempDirSuffix);
+}
+#endif
+
 bool gSafeMode = false;
 
 /**
  * The nsXULAppInfo object implements nsIFactory so that it can be its own
  * singleton.
  */
 class nsXULAppInfo : public nsIXULAppInfo,
 #ifdef E10S_TESTING_ONLY
@@ -4076,24 +4190,32 @@ XREMain::XRE_mainRun()
 
 #ifdef MOZ_INSTRUMENT_EVENT_LOOP
   if (PR_GetEnv("MOZ_INSTRUMENT_EVENT_LOOP")) {
     bool logToConsole = true;
     mozilla::InitEventTracing(logToConsole);
   }
 #endif /* MOZ_INSTRUMENT_EVENT_LOOP */
 
+#if defined(XP_WIN) && defined(MOZ_CONTENT_SANDBOX)
+  SetUpSandboxEnvironment();
+#endif
+
   {
     rv = appStartup->Run();
     if (NS_FAILED(rv)) {
       NS_ERROR("failed to run appstartup");
       gLogConsoleErrors = true;
     }
   }
 
+#if defined(XP_WIN) && defined(MOZ_CONTENT_SANDBOX)
+  CleanUpSandboxEnvironment();
+#endif
+
   return rv;
 }
 
 /*
  * XRE_main - A class based main entry point used by most platforms.
  *            Note that on OSX, aAppData->xreDirectory will point to
  *            .app/Contents/Resources.
  */
--- a/xpcom/io/nsDirectoryService.cpp
+++ b/xpcom/io/nsDirectoryService.cpp
@@ -19,20 +19,16 @@
 #include "nsISimpleEnumerator.h"
 #include "nsIStringEnumerator.h"
 
 #if defined(XP_WIN)
 #include <windows.h>
 #include <shlobj.h>
 #include <stdlib.h>
 #include <stdio.h>
-
-#if defined(MOZ_CONTENT_SANDBOX)
-#include "nsIUUIDGenerator.h"
-#endif
 #elif defined(XP_UNIX)
 #include <unistd.h>
 #include <stdlib.h>
 #include <sys/param.h>
 #include "prenv.h"
 #ifdef MOZ_WIDGET_COCOA
 #include <CoreServices/CoreServices.h>
 #include <Carbon/Carbon.h>
@@ -497,56 +493,31 @@ nsDirectoryService::UnregisterProvider(n
   }
 
   mProviders.RemoveElement(aProv);
   return NS_OK;
 }
 
 #if defined(MOZ_CONTENT_SANDBOX) && defined(XP_WIN)
 static nsresult
-GetLowIntegrityTemp(nsIFile** aLowIntegrityTemp)
+GetLowIntegrityTempBase(nsIFile** aLowIntegrityTempBase)
 {
   nsCOMPtr<nsIFile> localFile;
   nsresult rv = GetSpecialSystemDirectory(Win_LocalAppdataLow,
                                           getter_AddRefs(localFile));
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
-  nsCOMPtr<nsIUUIDGenerator> uuidgen =
-    do_GetService("@mozilla.org/uuid-generator;1", &rv);
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    return rv;
-  }
-
-  nsID uuid;
-  rv = uuidgen->GenerateUUIDInPlace(&uuid);
+  rv = localFile->Append(NS_LITERAL_STRING(MOZ_USER_DIR));
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
-  char uuidChars[NSID_LENGTH];
-  uuid.ToProvidedString(uuidChars);
-  rv = localFile->AppendNative(NS_LITERAL_CSTRING(MOZ_USER_DIR));
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    return rv;
-  }
-
-  rv = localFile->AppendNative(NS_LITERAL_CSTRING("MozTemp-")
-                               + nsDependentCString(uuidChars));
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    return rv;
-  }
-
-  rv = localFile->Create(nsIFile::DIRECTORY_TYPE, 0700);
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    return rv;
-  }
-
-  localFile.forget(aLowIntegrityTemp);
+  localFile.forget(aLowIntegrityTempBase);
   return rv;
 }
 #endif
 
 // DO NOT ADD ANY LOCATIONS TO THIS FUNCTION UNTIL YOU TALK TO: dougt@netscape.com.
 // This is meant to be a place of xpcom or system specific file locations, not
 // application specific locations.  If you need the later, register a callback for
 // your application.
@@ -717,18 +688,18 @@ nsDirectoryService::GetFile(const char* 
     rv = GetSpecialSystemDirectory(Win_Common_AppData, getter_AddRefs(localFile));
   } else if (inAtom == nsDirectoryService::sAppdata) {
     rv = GetSpecialSystemDirectory(Win_Appdata, getter_AddRefs(localFile));
   } else if (inAtom == nsDirectoryService::sLocalAppdata) {
     rv = GetSpecialSystemDirectory(Win_LocalAppdata, getter_AddRefs(localFile));
 #if defined(MOZ_CONTENT_SANDBOX)
   } else if (inAtom == nsDirectoryService::sLocalAppdataLow) {
     rv = GetSpecialSystemDirectory(Win_LocalAppdataLow, getter_AddRefs(localFile));
-  } else if (inAtom == nsDirectoryService::sLowIntegrityTemp) {
-    rv = GetLowIntegrityTemp(getter_AddRefs(localFile));
+  } else if (inAtom == nsDirectoryService::sLowIntegrityTempBase) {
+    rv = GetLowIntegrityTempBase(getter_AddRefs(localFile));
 #endif
   } else if (inAtom == nsDirectoryService::sPrinthood) {
     rv = GetSpecialSystemDirectory(Win_Printhood, getter_AddRefs(localFile));
   } else if (inAtom == nsDirectoryService::sWinCookiesDirectory) {
     rv = GetSpecialSystemDirectory(Win_Cookies, getter_AddRefs(localFile));
   } else if (inAtom == nsDirectoryService::sDefaultDownloadDirectory) {
     rv = GetSpecialSystemDirectory(Win_Downloads, getter_AddRefs(localFile));
   } else if (inAtom == nsDirectoryService::sDocs) {
--- a/xpcom/io/nsDirectoryServiceAtomList.h
+++ b/xpcom/io/nsDirectoryServiceAtomList.h
@@ -69,17 +69,17 @@ DIR_ATOM(sCommon_Startmenu, NS_WIN_COMMO
 DIR_ATOM(sCommon_Programs, NS_WIN_COMMON_PROGRAMS_DIR)
 DIR_ATOM(sCommon_Startup, NS_WIN_COMMON_STARTUP_DIR)
 DIR_ATOM(sCommon_Desktopdirectory, NS_WIN_COMMON_DESKTOP_DIRECTORY)
 DIR_ATOM(sCommon_AppData, NS_WIN_COMMON_APPDATA_DIR)
 DIR_ATOM(sAppdata, NS_WIN_APPDATA_DIR)
 DIR_ATOM(sLocalAppdata, NS_WIN_LOCAL_APPDATA_DIR)
 #if defined(MOZ_CONTENT_SANDBOX)
 DIR_ATOM(sLocalAppdataLow, NS_WIN_LOCAL_APPDATA_LOW_DIR)
-DIR_ATOM(sLowIntegrityTemp, NS_WIN_LOW_INTEGRITY_TEMP)
+DIR_ATOM(sLowIntegrityTempBase, NS_WIN_LOW_INTEGRITY_TEMP_BASE)
 #endif
 DIR_ATOM(sPrinthood, NS_WIN_PRINTHOOD)
 DIR_ATOM(sWinCookiesDirectory, NS_WIN_COOKIES_DIR)
 DIR_ATOM(sDefaultDownloadDirectory, NS_WIN_DEFAULT_DOWNLOAD_DIR)
 DIR_ATOM(sDocs, NS_WIN_DOCUMENTS_DIR)
 DIR_ATOM(sPictures, NS_WIN_PICTURES_DIR)
 DIR_ATOM(sMusic, NS_WIN_MUSIC_DIR)
 DIR_ATOM(sVideos, NS_WIN_VIDEOS_DIR)
--- a/xpcom/io/nsDirectoryServiceDefs.h
+++ b/xpcom/io/nsDirectoryServiceDefs.h
@@ -126,17 +126,17 @@
   #define NS_WIN_COMMON_PROGRAMS_DIR          "CmPrgs"
   #define NS_WIN_COMMON_STARTUP_DIR           "CmStrt"
   #define NS_WIN_COMMON_DESKTOP_DIRECTORY     "CmDeskP"
   #define NS_WIN_COMMON_APPDATA_DIR           "CmAppData"
   #define NS_WIN_APPDATA_DIR                  "AppData"
   #define NS_WIN_LOCAL_APPDATA_DIR            "LocalAppData"
 #if defined(MOZ_CONTENT_SANDBOX)
   #define NS_WIN_LOCAL_APPDATA_LOW_DIR        "LocalAppDataLow"
-  #define NS_WIN_LOW_INTEGRITY_TEMP           "LowTmpD"
+  #define NS_WIN_LOW_INTEGRITY_TEMP_BASE      "LowTmpDBase"
 #endif
   #define NS_WIN_PRINTHOOD                    "PrntHd"
   #define NS_WIN_COOKIES_DIR                  "CookD"
   #define NS_WIN_DEFAULT_DOWNLOAD_DIR         "DfltDwnld"
   // On Win7 and up these ids will return the default save-to location for
   // Windows Libraries associated with the specific content type. For other
   // os they return the local user folder. Note these can return network file
   // paths which can jank the ui thread so be careful how you access them.