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
--- 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()