Bug 1237847 - [e10s] Null deref crash when running test_pluginstream_newstream.html; r=bobowen
authorHaik Aftandilian <haftandilian@mozilla.com>
Thu, 25 Feb 2016 15:26:13 -0800
changeset 322143 5b20181a5b50b92259038a88202b2ece37e2b702
parent 322142 c4d101e34585cb7950189fc1f4aa0bf99dec8041
child 322144 5e0cf0c0f8c3c6c46698e3f7d3181db1032d045d
push id5913
push userjlund@mozilla.com
push dateMon, 25 Apr 2016 16:57:49 +0000
treeherdermozilla-beta@dcaf0a6fa115 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbobowen
bugs1237847
milestone47.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 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
@@ -598,52 +598,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))) {
@@ -673,47 +707,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.
@@ -4268,29 +4304,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()