Bug 1237847 - [e10s] Null deref crash when running test_pluginstream_newstream.html; r=bobowen draft
authorHaik Aftandilian <haftandilian@mozilla.com>
Thu, 25 Feb 2016 15:26:13 -0800
changeset 334728 a77624d97130d980dd1caa43f8de21c040646c59
parent 334101 d848a5628d801a460a7244cbcdea22d328d8b310
child 514983 51f7fda59d7d0396c3ec9838c0e8ec2699b326d4
push id11624
push userhaftandilian@mozilla.com
push dateThu, 25 Feb 2016 23:30:39 +0000
reviewersbobowen
bugs1237847
milestone47.0a1
Bug 1237847 - [e10s] Null deref crash when running test_pluginstream_newstream.html; r=bobowen Modify the Mac sandbox to allow temporary files to be created in a parent-specified subdirectory of NS_OS_TEMP_DIR. This is similar to the Windows approach. The parent provides a UUID in a preference which is used by the content process to form the subdirectory name. MozReview-Commit-ID: 6BONpfZz8ZI
browser/app/profile/firefox.js
dom/ipc/ContentChild.cpp
dom/ipc/ContentProcess.cpp
dom/plugins/test/mochitest/mochitest.ini
security/sandbox/mac/Sandbox.h
security/sandbox/mac/Sandbox.mm
toolkit/xre/nsAppRunner.cpp
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -1196,20 +1196,16 @@ pref("dom.ipc.plugins.sandbox-level.flas
 // See - security/sandbox/win/src/sandboxbroker/sandboxBroker.cpp
 // SetSecurityLevelForContentProcess() for what the different settings mean.
 #if defined(NIGHTLY_BUILD)
 pref("security.sandbox.content.level", 2);
 #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
 #endif
@@ -1222,16 +1218,25 @@ pref("security.sandbox.windows.log.stack
 // 1 -> "an imperfect sandbox designed to allow firefox to run reasonably well"
 // 2 -> "an ideal sandbox which may break many things"
 // This setting is read when the content process is started. On Mac the content
 // process is killed when all windows are closed, so a change will take effect
 // when the 1st window is opened.
 pref("security.sandbox.content.level", 1);
 #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
+
 // This pref governs whether we attempt to work around problems caused by
 // plugins using OS calls to manipulate the cursor while running out-of-
 // process.  These workarounds all involve intercepting (hooking) certain
 // OS calls in the plugin process, then arranging to make certain OS calls
 // in the browser process.  Eventually plugins will be required to use the
 // NPAPI to manipulate the cursor, and these workarounds will be removed.
 // See bug 621117.
 #ifdef XP_MACOSX
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -97,16 +97,17 @@
 #include "nsDebugImpl.h"
 #include "nsHashPropertyBag.h"
 #include "nsLayoutStylesheetCache.h"
 #include "nsThreadManager.h"
 #include "nsAnonymousTemporaryFile.h"
 #include "nsISpellChecker.h"
 #include "nsClipboardProxy.h"
 #include "nsISystemMessageCache.h"
+#include "nsDirectoryService.h"
 #include "nsDirectoryServiceUtils.h"
 #include "nsDirectoryServiceDefs.h"
 #include "nsContentPermissionHelper.h"
 
 #include "IHistory.h"
 #include "nsNetUtil.h"
 
 #include "base/message_loop.h"
@@ -1405,22 +1406,39 @@ GetAppPaths(nsCString &aAppPath, nsCStri
 static void
 StartMacOSContentSandbox()
 {
   nsAutoCString appPath, appBinaryPath, appDir;
   if (!GetAppPaths(appPath, appBinaryPath, appDir)) {
     MOZ_CRASH("Error resolving child process path");
   }
 
+  // During sandboxed content process startup, before reaching
+  // this point, NS_OS_TEMP_DIR is modified to refer to a sandbox-
+  // writable temporary directory
+  nsCOMPtr<nsIFile> tempDir;
+  nsresult rv = nsDirectoryService::gService->Get(NS_OS_TEMP_DIR,
+      NS_GET_IID(nsIFile), getter_AddRefs(tempDir));
+  if (NS_FAILED(rv)) {
+    MOZ_CRASH("Failed to get NS_OS_TEMP_DIR");
+  }
+
+  nsAutoCString tempDirPath;
+  rv = tempDir->GetNativePath(tempDirPath);
+  if (NS_FAILED(rv)) {
+    MOZ_CRASH("Failed to get NS_OS_TEMP_DIR path");
+  }
+
   MacSandboxInfo info;
   info.type = MacSandboxType_Content;
   info.level = Preferences::GetInt("security.sandbox.content.level");
   info.appPath.assign(appPath.get());
   info.appBinaryPath.assign(appBinaryPath.get());
   info.appDir.assign(appDir.get());
+  info.appTempDir.assign(tempDirPath.get());
 
   std::string err;
   if (!mozilla::StartMacSandbox(info, err)) {
     NS_WARNING(err.c_str());
     MOZ_CRASH("sandbox_init() failed");
   }
 }
 #endif
--- a/dom/ipc/ContentProcess.cpp
+++ b/dom/ipc/ContentProcess.cpp
@@ -4,64 +4,98 @@
  * 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_WIN) || defined(XP_MACOSX)) && 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 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 const char*
+SandboxTempDirParent()
+{
+  // On Windows, the sandbox-writable temp directory resides in the
+  // low integrity sandbox base directory.
+  return NS_WIN_LOW_INTEGRITY_TEMP_BASE;
+}
+#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 const char*
+SandboxTempDirParent()
+{
+  return NS_OS_TEMP_DIR;
+}
+#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.");
+    NS_WARNING("Sandbox-writable temp directory suffix pref not set.");
     return;
   }
 
-  // Get the base low integrity Mozilla temp directory.
+  // Get the parent of our sandbox writable temp directory.
   nsCOMPtr<nsIFile> lowIntegrityTemp;
-  nsresult rv = nsDirectoryService::gService->Get(NS_WIN_LOW_INTEGRITY_TEMP_BASE,
+  nsresult rv = nsDirectoryService::gService->Get(SandboxTempDirParent(),
                                                   NS_GET_IID(nsIFile),
                                                   getter_AddRefs(lowIntegrityTemp));
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return;
   }
 
   // Append our profile specific temp name.
   rv = lowIntegrityTemp->Append(NS_LITERAL_STRING("Temp-") + tempDirSuffix);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return;
   }
 
-  // Change the gecko defined temp directory to our low integrity one.
+  // 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, lowIntegrityTemp);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return;
   }
 }
 #endif
@@ -77,20 +111,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/dom/plugins/test/mochitest/mochitest.ini
+++ b/dom/plugins/test/mochitest/mochitest.ini
@@ -93,17 +93,16 @@ skip-if = buildapp == 'mulet' || buildap
 [test_plugin_scroll_painting.html]
 skip-if = true # Bug 596491
 [test_pluginstream_asfile.html]
 [test_pluginstream_asfileonly.html]
 [test_pluginstream_err.html]
 [test_pluginstream_geturl.html]
 [test_pluginstream_geturlnotify.html]
 [test_pluginstream_newstream.html]
-skip-if = (e10s && debug) # Bug 1237847
 [test_pluginstream_post.html]
 [test_pluginstream_poststream.html]
 [test_pluginstream_referer.html]
 [test_pluginstream_seek.html]
 [test_pluginstream_seek_close.html]
 [test_pluginstream_src.html]
 [test_pluginstream_src_dynamic.html]
 [test_pluginstream_src_referer.html]
--- a/security/sandbox/mac/Sandbox.h
+++ b/security/sandbox/mac/Sandbox.h
@@ -42,16 +42,17 @@ typedef struct _MacSandboxInfo {
       appPath(other.appPath), appBinaryPath(other.appBinaryPath),
       appDir(other.appDir) {}
   MacSandboxType type;
   int32_t level;
   MacSandboxPluginInfo pluginInfo;
   std::string appPath;
   std::string appBinaryPath;
   std::string appDir;
+  std::string appTempDir;
 } MacSandboxInfo;
 
 namespace mozilla {
 
 bool StartMacSandbox(MacSandboxInfo aInfo, std::string &aErrorMessage);
 
 } // namespace mozilla
 
--- a/security/sandbox/mac/Sandbox.mm
+++ b/security/sandbox/mac/Sandbox.mm
@@ -153,16 +153,17 @@ static const char pluginSandboxRules[] =
 static const char contentSandboxRules[] =
   "(version 1)\n"
   "\n"
   "(define sandbox-level %d)\n"
   "(define macosMinorVersion %d)\n"
   "(define appPath \"%s\")\n"
   "(define appBinaryPath \"%s\")\n"
   "(define appDir \"%s\")\n"
+  "(define appTempDir \"%s\")\n"
   "(define home-path \"%s\")\n"
   "\n"
   "(import \"/System/Library/Sandbox/Profiles/system.sb\")\n"
   "\n"
   "(if \n"
   "  (or\n"
   "    (< macosMinorVersion 9)\n"
   "    (< sandbox-level 1))\n"
@@ -416,16 +417,22 @@ static const char contentSandboxRules[] 
   "\n"
   "; bug 1190032\n"
   "    (allow file*\n"
   "        (home-regex \"/Library/Caches/TemporaryItems/plugtmp.*\"))\n"
   "\n"
   "; bug 1201935\n"
   "    (allow file-read*\n"
   "        (home-subpath \"/Library/Caches/TemporaryItems\"))\n"
+  "\n"
+  "; bug 1237847\n"
+  "    (allow file-read*\n"
+  "        (home-subpath appTempDir))\n"
+  "    (allow file-write*\n"
+  "        (home-subpath appTempDir))\n"
   "  )\n"
   ")\n";
 
 bool StartMacSandbox(MacSandboxInfo aInfo, std::string &aErrorMessage)
 {
   char *profile = NULL;
   if (aInfo.type == MacSandboxType_Plugin) {
     if (OSXVersion::OnLionOrLater()) {
@@ -443,16 +450,17 @@ bool StartMacSandbox(MacSandboxInfo aInf
     }
   }
   else if (aInfo.type == MacSandboxType_Content) {
     asprintf(&profile, contentSandboxRules, aInfo.level,
              OSXVersion::OSXVersionMinor(),
              aInfo.appPath.c_str(),
              aInfo.appBinaryPath.c_str(),
              aInfo.appDir.c_str(),
+             aInfo.appTempDir.c_str(),
              getenv("HOME"));
   }
   else {
     char *msg = NULL;
     asprintf(&msg, "Unexpected sandbox type %u", aInfo.type);
     if (msg) {
       aErrorMessage.assign(msg);
       free(msg);
--- a/toolkit/xre/nsAppRunner.cpp
+++ b/toolkit/xre/nsAppRunner.cpp
@@ -600,52 +600,86 @@ ProcessDDE(nsINativeAppSupport* aNative,
 */
 static bool
 CanShowProfileManager()
 {
   return true;
 }
 
 #if defined(XP_WIN) && defined(MOZ_CONTENT_SANDBOX)
-static already_AddRefed<nsIFile>
-GetAndCleanLowIntegrityTemp(const nsAString& aTempDirSuffix)
+static const char*
+SandboxTempDirParent()
+{
+  return NS_WIN_LOW_INTEGRITY_TEMP_BASE;
+}
+#endif
+
+#if defined(XP_MACOSX) && defined(MOZ_CONTENT_SANDBOX)
+static const char*
+SandboxTempDirParent()
 {
-  // Get the base low integrity Mozilla temp directory.
-  nsCOMPtr<nsIFile> lowIntegrityTemp;
-  nsresult rv = NS_GetSpecialDirectory(NS_WIN_LOW_INTEGRITY_TEMP_BASE,
-                                       getter_AddRefs(lowIntegrityTemp));
+  return NS_OS_TEMP_DIR;
+}
+#endif
+
+#if (defined(XP_WIN) || defined(XP_MACOSX)) && defined(MOZ_CONTENT_SANDBOX)
+static already_AddRefed<nsIFile>
+GetAndCleanTempDir(const nsAString& aTempDirSuffix)
+{
+  // Get the directory within which we'll place the
+  // sandbox-writable temp directory
+  nsCOMPtr<nsIFile> tempDir;
+  nsresult rv = NS_GetSpecialDirectory(SandboxTempDirParent(),
+      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);
+  rv = tempDir->Append(NS_LITERAL_STRING("Temp-") + aTempDirSuffix);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return nullptr;
   }
 
-  rv = lowIntegrityTemp->Remove(/* aRecursive */ true);
+  rv = tempDir->Remove(/* aRecursive */ true);
   if (NS_FAILED(rv) && rv != NS_ERROR_FILE_NOT_FOUND) {
-    NS_WARNING("Failed to delete low integrity temp directory.");
+    NS_WARNING("Failed to delete 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))) {
@@ -675,47 +709,49 @@ 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(tempDirSuffix);
+  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;
   }
 }
 
 static void
 CleanUpSandboxEnvironment()
 {
-  // We can't have created a low integrity temp before Vista.
+#if defined(XP_WIN)
+  // We can't have created the temp directory before Vista.
   if (!IsVistaOrLater()) {
     return;
   }
+#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.
+  // Get and remove the sandbox-writable temp directory.
   // This function already warns if the deletion fails.
-  nsCOMPtr<nsIFile> lowIntegrityTemp = GetAndCleanLowIntegrityTemp(tempDirSuffix);
+  nsCOMPtr<nsIFile> tempDir = GetAndCleanTempDir(tempDirSuffix);
 }
 #endif
 
 bool gSafeMode = false;
 
 /**
  * The nsXULAppInfo object implements nsIFactory so that it can be its own
  * singleton.
@@ -4270,29 +4306,29 @@ 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)
+#if (defined(XP_WIN) || defined(XP_MACOSX)) && 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)
+#if (defined(XP_WIN) || defined(XP_MACOSX)) && defined(MOZ_CONTENT_SANDBOX)
   CleanUpSandboxEnvironment();
 #endif
 
   return rv;
 }
 
 #if MOZ_WIDGET_GTK == 2
 void XRE_GlibInit()