Bug 1018966 - Part 1: Add the main warn only sandbox machinery - with no Chromium code changes. r=bsmedberg
authorBob Owen <bobowencode@gmail.com>
Wed, 11 Jun 2014 15:32:37 +0100
changeset 226984 7be34c88c9ac2ae5759bfa4cd707d96edfe90200
parent 226983 1de381da53b58ecf0c5afa064f872b788e7c8e9d
child 226985 e7eef85c1b0af39ddd5e0f16ce91bf6bfa4ac6d1
push id4187
push userbhearsum@mozilla.com
push dateFri, 28 Nov 2014 15:29:12 +0000
treeherdermozilla-beta@f23cc6a30c11 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbsmedberg
bugs1018966
milestone35.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 1018966 - Part 1: Add the main warn only sandbox machinery - with no Chromium code changes. r=bsmedberg This change also includes the content sandboxing code on Windows Nightly by defining MOZ_CONTENT_SANDBOX=1. Whether the content sandbox is disabled, in warn only mode, or enabled is controlled by a new pref: browser.tabs.remote.sandbox=(off/warn/on)
browser/app/moz.build
browser/app/profile/firefox.js
configure.in
dom/ipc/ContentChild.cpp
ipc/contentproc/plugin-container.cpp
ipc/glue/GeckoChildProcessHost.cpp
ipc/glue/GeckoChildProcessHost.h
security/sandbox/moz.build
security/sandbox/objs.mozbuild
security/sandbox/win/src/sandboxbroker/sandboxBroker.cpp
security/sandbox/win/src/sandboxbroker/sandboxBroker.h
security/sandbox/win/src/warnonlysandbox/warnOnlySandbox.cpp
security/sandbox/win/src/warnonlysandbox/warnOnlySandbox.h
security/sandbox/win/src/warnonlysandbox/wosCallbacks.h
security/sandbox/win/src/warnonlysandbox/wosTypes.h
toolkit/xre/moz.build
toolkit/xre/nsEmbedFunctions.cpp
--- a/browser/app/moz.build
+++ b/browser/app/moz.build
@@ -67,8 +67,11 @@ else:
 
 DISABLE_STL_WRAPPING = True
 
 if CONFIG['MOZ_LINKER']:
     OS_LIBS += CONFIG['MOZ_ZLIB_LIBS']
 
 if CONFIG['HAVE_CLOCK_MONOTONIC']:
     OS_LIBS += CONFIG['REALTIME_LIBS']
+
+if CONFIG['MOZ_OPTIMIZE']:
+    DEFINES['MOZ_OPTIMIZE'] = True
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -1179,16 +1179,35 @@ pref("dom.ipc.plugins.enabled", true);
 // browser.tabs.remote.autostart or they use the "New OOP Window" menu
 // option.
 pref("browser.tabs.remote", true);
 #else
 pref("browser.tabs.remote", false);
 #endif
 pref("browser.tabs.remote.autostart", false);
 
+#if defined(MOZ_CONTENT_SANDBOX) && defined(XP_WIN)
+// This controls whether the content process on Windows is sandboxed.
+// You also need to be using remote tabs, see above.
+// on = full sandbox enabled
+// warn = warn only sandbox enabled
+// anything else = sandbox disabled
+// This will probably require a restart.
+pref("browser.tabs.remote.sandbox", "off");
+
+// This is essentially the same logic that decides whether nsStackWalk.cpp gets
+// built, which we use for the stack trace. See xpcom/base/moz.build
+#if !defined(MOZ_OPTIMIZE) || defined(MOZ_PROFILING) || defined(DEBUG)
+// This controls the depth of stack trace that is logged when the warn only
+// sandbox reports that a resource access request has been blocked.
+// This does not require a restart to take effect.
+pref("browser.tabs.remote.sandbox.warnOnlyStackTraceDepth", 0);
+#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/configure.in
+++ b/configure.in
@@ -6390,20 +6390,27 @@ MOZ_ARG_DISABLE_BOOL(sandbox,
 
 dnl ========================================================
 dnl = Content process sandboxing
 dnl ========================================================
 if test -n "$gonkdir"; then
     MOZ_CONTENT_SANDBOX=$MOZ_SANDBOX
 fi
 
-MOZ_ARG_ENABLE_BOOL(content-sandbox,
-[  --enable-content-sandbox        Enable sandboxing support for content-processes],
-    MOZ_CONTENT_SANDBOX=1,
-    MOZ_CONTENT_SANDBOX=)
+case "$OS_TARGET:$NIGHTLY_BUILD" in
+WINNT:1)
+    MOZ_CONTENT_SANDBOX=$MOZ_SANDBOX
+    ;;
+*)
+    MOZ_ARG_ENABLE_BOOL(content-sandbox,
+    [  --enable-content-sandbox        Enable sandboxing support for content-processes],
+        MOZ_CONTENT_SANDBOX=1,
+        MOZ_CONTENT_SANDBOX=)
+    ;;
+esac
 
 if test -n "$MOZ_CONTENT_SANDBOX"; then
     AC_DEFINE(MOZ_CONTENT_SANDBOX)
 fi
 
 AC_SUBST(MOZ_CONTENT_SANDBOX)
 
 dnl ========================================================
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -937,17 +937,22 @@ ContentChild::RecvSetProcessSandbox()
 #else
     // Otherwise, sandboxing is best-effort.
     if (!CanSandboxContentProcess()) {
         return true;
     }
 #endif
     SetContentProcessSandbox();
 #elif defined(XP_WIN)
-    mozilla::SandboxTarget::Instance()->StartSandbox();
+    nsAdoptingString contentSandboxPref =
+        Preferences::GetString("browser.tabs.remote.sandbox");
+    if (contentSandboxPref.EqualsLiteral("on")
+        || contentSandboxPref.EqualsLiteral("warn")) {
+        mozilla::SandboxTarget::Instance()->StartSandbox();
+    }
 #endif
 #endif
     return true;
 }
 
 bool
 ContentChild::RecvSpeakerManagerNotify()
 {
--- a/ipc/contentproc/plugin-container.cpp
+++ b/ipc/contentproc/plugin-container.cpp
@@ -21,16 +21,20 @@
 #include "nsSetDllDirectory.h"
 #endif
 
 #if defined(XP_WIN) && defined(MOZ_SANDBOX)
 #include "sandbox/chromium/base/basictypes.h"
 #include "sandbox/win/src/sandbox.h"
 #include "sandbox/win/src/sandbox_factory.h"
 #include "mozilla/sandboxTarget.h"
+
+#if defined(MOZ_CONTENT_SANDBOX)
+#include "mozilla/warnonlysandbox/wosCallbacks.h"
+#endif
 #endif
 
 #ifdef MOZ_WIDGET_GONK
 # include <sys/time.h>
 # include <sys/resource.h> 
 
 # include <binder/ProcessState.h>
 
@@ -138,16 +142,20 @@ content_process_main(int argc, char* arg
             return 1;
         }
 
         sandbox::ResultCode result = target_service->Init();
         if (result != sandbox::SBOX_ALL_OK) {
            return 2;
         }
         mozilla::SandboxTarget::Instance()->SetStartSandboxCallback(StartSandboxCallback);
+
+#if defined(MOZ_CONTENT_SANDBOX)
+        mozilla::warnonlysandbox::PrepareForInit();
+#endif
     }
 #endif
 #endif
 
     nsresult rv = XRE_InitChildProcess(argc, argv);
     NS_ENSURE_SUCCESS(rv, 1);
 
     return 0;
--- a/ipc/glue/GeckoChildProcessHost.cpp
+++ b/ipc/glue/GeckoChildProcessHost.cpp
@@ -29,16 +29,21 @@
 #include "mozilla/ClearOnShutdown.h"
 #include "mozilla/ipc/BrowserProcessSubThread.h"
 #include "mozilla/Omnijar.h"
 #include <sys/stat.h>
 
 #ifdef XP_WIN
 #include "nsIWinTaskbar.h"
 #define NS_TASKBAR_CONTRACTID "@mozilla.org/windows-taskbar;1"
+
+#if defined(MOZ_CONTENT_SANDBOX)
+#include "mozilla/Preferences.h"
+#include "mozilla/warnonlysandbox/warnOnlySandbox.h"
+#endif
 #endif
 
 #include "nsTArray.h"
 #include "nsClassHashtable.h"
 #include "nsHashKeys.h"
 #include "nsNativeCharsetUtils.h"
 
 using mozilla::MonitorAutoLock;
@@ -85,16 +90,20 @@ GeckoChildProcessHost::DefaultChildPrivi
 GeckoChildProcessHost::GeckoChildProcessHost(GeckoProcessType aProcessType,
                                              ChildPrivileges aPrivileges)
   : ChildProcessHost(RENDER_PROCESS), // FIXME/cjones: we should own this enum
     mProcessType(aProcessType),
     mPrivileges(aPrivileges),
     mMonitor("mozilla.ipc.GeckChildProcessHost.mMonitor"),
     mProcessState(CREATING_CHANNEL),
     mDelegate(nullptr),
+#if defined(MOZ_CONTENT_SANDBOX) && defined(XP_WIN)
+    mEnableContentSandbox(false),
+    mWarnOnlyContentSandbox(false),
+#endif
     mChildProcessHandle(0)
 #if defined(MOZ_WIDGET_COCOA)
   , mChildTask(MACH_PORT_NULL)
 #endif
 {
     MOZ_COUNT_CTOR(GeckoChildProcessHost);
 }
 
@@ -245,16 +254,30 @@ GeckoChildProcessHost::PrepareLaunch()
     CrashReporter::OOPInit();
   }
 #endif
 
 #ifdef XP_WIN
   if (mProcessType == GeckoProcessType_Plugin) {
     InitWindowsGroupID();
   }
+
+#if defined(MOZ_CONTENT_SANDBOX)
+  // We need to get the pref here as the process is launched off main thread.
+  if (mProcessType == GeckoProcessType_Content) {
+    nsAdoptingString contentSandboxPref =
+      Preferences::GetString("browser.tabs.remote.sandbox");
+    if (contentSandboxPref.EqualsLiteral("on")) {
+      mEnableContentSandbox = true;
+    } else if (contentSandboxPref.EqualsLiteral("warn")) {
+      mEnableContentSandbox = true;
+      mWarnOnlyContentSandbox = true;
+    }
+  }
+#endif
 #endif
 }
 
 #ifdef XP_WIN
 void GeckoChildProcessHost::InitWindowsGroupID()
 {
   // On Win7+, pass the application user model to the child, so it can
   // register with it. This insures windows created by the container
@@ -755,18 +778,21 @@ GeckoChildProcessHost::PerformAsyncLaunc
     }
   }
 
 #if defined(XP_WIN)
   bool shouldSandboxCurrentProcess = false;
   switch (mProcessType) {
     case GeckoProcessType_Content:
 #if defined(MOZ_CONTENT_SANDBOX)
+      if (!mEnableContentSandbox) {
+        break;
+      }
       if (!PR_GetEnv("MOZ_DISABLE_CONTENT_SANDBOX")) {
-        mSandboxBroker.SetSecurityLevelForContentProcess();
+        mSandboxBroker.SetSecurityLevelForContentProcess(mWarnOnlyContentSandbox);
         cmdLine.AppendLooseValue(UTF8ToWide("-sandbox"));
         shouldSandboxCurrentProcess = true;
       }
 #endif // MOZ_CONTENT_SANDBOX
       break;
     case GeckoProcessType_Plugin:
       // XXX: We don't sandbox this process type yet
       // mSandboxBroker.SetSecurityLevelForPluginProcess();
--- a/ipc/glue/GeckoChildProcessHost.h
+++ b/ipc/glue/GeckoChildProcessHost.h
@@ -164,16 +164,21 @@ protected:
 
 #ifdef XP_WIN
   void InitWindowsGroupID();
   nsString mGroupId;
 
 #ifdef MOZ_SANDBOX
   SandboxBroker mSandboxBroker;
   std::vector<std::wstring> mAllowedFilesRead;
+
+#if defined(MOZ_CONTENT_SANDBOX)
+  bool mEnableContentSandbox;
+  bool mWarnOnlyContentSandbox;
+#endif
 #endif
 #endif // XP_WIN
 
 #if defined(OS_POSIX)
   base::file_handle_mapping_vector mFileMap;
 #endif
 
   base::WaitableEventWatcher::Delegate* mDelegate;
--- a/security/sandbox/moz.build
+++ b/security/sandbox/moz.build
@@ -13,16 +13,23 @@ elif CONFIG['OS_ARCH'] == 'WINNT':
     FORCE_STATIC_LIB = True
 
     DIRS += [
         'staticruntime',
         'win/src/sandboxbroker',
         'win/src/sandboxtarget',
     ]
 
+    if CONFIG['MOZ_CONTENT_SANDBOX']:
+        EXPORTS.mozilla.warnonlysandbox += [
+            'win/src/warnonlysandbox/warnOnlySandbox.h',
+            'win/src/warnonlysandbox/wosCallbacks.h',
+            'win/src/warnonlysandbox/wosTypes.h',
+        ]
+
     include('objs.mozbuild')
     SOURCES += security_sandbox_cppsrcs
 
     for var in ('UNICODE', '_UNICODE', 'NS_NO_XPCOM', 'SANDBOX_EXPORTS',
                 'NOMINMAX', '_CRT_RAND_S', 'CHROMIUM_SANDBOX_BUILD'):
         DEFINES[var] = True
 
     LOCAL_INCLUDES += ['/security/sandbox/chromium/base/shim']
--- a/security/sandbox/objs.mozbuild
+++ b/security/sandbox/objs.mozbuild
@@ -94,16 +94,21 @@ if CONFIG['OS_ARCH'] == 'WINNT':
         'win/src/target_interceptions.cc',
         'win/src/target_process.cc',
         'win/src/target_services.cc',
         'win/src/win2k_threadpool.cc',
         'win/src/win_utils.cc',
         'win/src/window.cc',
     ]
 
+    if CONFIG['MOZ_CONTENT_SANDBOX']:
+        security_sandbox_lcppsrcs += [
+            'win/src/warnonlysandbox/warnOnlySandbox.cpp',
+        ]
+
     if CONFIG['CPU_ARCH'] == 'x86_64':
         security_sandbox_lcppsrcs += [
             'win/src/interceptors_64.cc',
             'win/src/resolver_64.cc',
             'win/src/service_resolver_64.cc',
             'win/src/Wow64_64.cc',
         ]
     else:
--- a/security/sandbox/win/src/sandboxbroker/sandboxBroker.cpp
+++ b/security/sandbox/win/src/sandboxbroker/sandboxBroker.cpp
@@ -3,16 +3,19 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * 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 "sandboxBroker.h"
 #include "sandbox/win/src/sandbox.h"
 #include "sandbox/win/src/sandbox_factory.h"
 #include "sandbox/win/src/security_level.h"
+#if defined(MOZ_CONTENT_SANDBOX)
+#include "mozilla/warnonlysandbox/warnOnlySandbox.h"
+#endif
 
 namespace mozilla
 {
 
 sandbox::BrokerServices *SandboxBroker::sBrokerService = nullptr;
 
 SandboxBroker::SandboxBroker()
 {
@@ -55,36 +58,42 @@ SandboxBroker::LaunchApp(const wchar_t *
   CloseHandle(targetInfo.hThread);
 
   // Return the process handle to the caller
   *aProcessHandle = targetInfo.hProcess;
 
   return true;
 }
 
+#if defined(MOZ_CONTENT_SANDBOX)
 bool
-SandboxBroker::SetSecurityLevelForContentProcess()
+SandboxBroker::SetSecurityLevelForContentProcess(bool inWarnOnlyMode)
 {
   if (!mPolicy) {
     return false;
   }
 
   auto result = mPolicy->SetJobLevel(sandbox::JOB_NONE, 0);
   bool ret = (sandbox::SBOX_ALL_OK == result);
   result =
     mPolicy->SetTokenLevel(sandbox::USER_RESTRICTED_SAME_ACCESS,
                            sandbox::USER_RESTRICTED_SAME_ACCESS);
   ret = ret && (sandbox::SBOX_ALL_OK == result);
   result =
     mPolicy->SetDelayedIntegrityLevel(sandbox::INTEGRITY_LEVEL_LOW);
   ret = ret && (sandbox::SBOX_ALL_OK == result);
   result = mPolicy->SetAlternateDesktop(true);
   ret = ret && (sandbox::SBOX_ALL_OK == result);
+
+  if (inWarnOnlyMode) {
+    mozilla::warnonlysandbox::ApplyWarnOnlyPolicy(*mPolicy);
+  }
   return ret;
 }
+#endif
 
 bool
 SandboxBroker::SetSecurityLevelForPluginProcess()
 {
   if (!mPolicy) {
     return false;
   }
 
--- a/security/sandbox/win/src/sandboxbroker/sandboxBroker.h
+++ b/security/sandbox/win/src/sandboxbroker/sandboxBroker.h
@@ -25,17 +25,19 @@ class SANDBOX_EXPORT SandboxBroker
 public:
   SandboxBroker();
   bool LaunchApp(const wchar_t *aPath,
                  const wchar_t *aArguments,
                  void **aProcessHandle);
   virtual ~SandboxBroker();
 
   // Security levels for different types of processes
-  bool SetSecurityLevelForContentProcess();
+#if defined(MOZ_CONTENT_SANDBOX)
+  bool SetSecurityLevelForContentProcess(bool inWarnOnlyMode);
+#endif
   bool SetSecurityLevelForPluginProcess();
   bool SetSecurityLevelForIPDLUnitTestProcess();
   bool SetSecurityLevelForGMPlugin();
 
   // File system permissions
   bool AllowReadFile(wchar_t const *file);
   bool AllowReadWriteFile(wchar_t const *file);
   bool AllowDirectory(wchar_t const *dir);
new file mode 100644
--- /dev/null
+++ b/security/sandbox/win/src/warnonlysandbox/warnOnlySandbox.cpp
@@ -0,0 +1,123 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * 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 "warnOnlySandbox.h"
+
+#include "base/strings/utf_string_conversions.h"
+#include "sandbox/win/src/sandbox_policy.h"
+
+namespace mozilla {
+namespace warnonlysandbox {
+
+void
+ApplyWarnOnlyPolicy(sandbox::TargetPolicy& aPolicy)
+{
+  // Add rules to allow everything that we can, so that we can add logging to
+  // warn when we would be blocked by the sandbox.
+  aPolicy.AddRule(sandbox::TargetPolicy::SUBSYS_FILES,
+                  sandbox::TargetPolicy::FILES_ALLOW_ANY, L"*");
+  aPolicy.AddRule(sandbox::TargetPolicy::SUBSYS_NAMED_PIPES,
+                  sandbox::TargetPolicy::NAMEDPIPES_ALLOW_ANY, L"*");
+  aPolicy.AddRule(sandbox::TargetPolicy::SUBSYS_PROCESS,
+                  sandbox::TargetPolicy::PROCESS_ALL_EXEC, L"*");
+  aPolicy.AddRule(sandbox::TargetPolicy::SUBSYS_REGISTRY,
+                  sandbox::TargetPolicy::REG_ALLOW_ANY,
+                  L"HKEY_CLASSES_ROOT\\*");
+  aPolicy.AddRule(sandbox::TargetPolicy::SUBSYS_REGISTRY,
+                  sandbox::TargetPolicy::REG_ALLOW_ANY,
+                  L"HKEY_CURRENT_USER\\*");
+  aPolicy.AddRule(sandbox::TargetPolicy::SUBSYS_REGISTRY,
+                  sandbox::TargetPolicy::REG_ALLOW_ANY,
+                  L"HKEY_LOCAL_MACHINE\\*");
+  aPolicy.AddRule(sandbox::TargetPolicy::SUBSYS_REGISTRY,
+                  sandbox::TargetPolicy::REG_ALLOW_ANY,
+                  L"HKEY_USERS\\*");
+  aPolicy.AddRule(sandbox::TargetPolicy::SUBSYS_REGISTRY,
+                  sandbox::TargetPolicy::REG_ALLOW_ANY,
+                  L"HKEY_PERFORMANCE_DATA\\*");
+  aPolicy.AddRule(sandbox::TargetPolicy::SUBSYS_REGISTRY,
+                  sandbox::TargetPolicy::REG_ALLOW_ANY,
+                  L"HKEY_PERFORMANCE_TEXT\\*");
+  aPolicy.AddRule(sandbox::TargetPolicy::SUBSYS_REGISTRY,
+                  sandbox::TargetPolicy::REG_ALLOW_ANY,
+                  L"HKEY_PERFORMANCE_NLSTEXT\\*");
+  aPolicy.AddRule(sandbox::TargetPolicy::SUBSYS_REGISTRY,
+                  sandbox::TargetPolicy::REG_ALLOW_ANY,
+                  L"HKEY_CURRENT_CONFIG\\*");
+  aPolicy.AddRule(sandbox::TargetPolicy::SUBSYS_REGISTRY,
+                  sandbox::TargetPolicy::REG_ALLOW_ANY,
+                  L"HKEY_DYN_DATA\\*");
+  aPolicy.AddRule(sandbox::TargetPolicy::SUBSYS_SYNC,
+                  sandbox::TargetPolicy::EVENTS_ALLOW_ANY, L"*");
+  aPolicy.AddRule(sandbox::TargetPolicy::SUBSYS_HANDLES,
+                  sandbox::TargetPolicy::HANDLES_DUP_ANY, L"*");
+}
+
+static LogFunction sLogFunction = nullptr;
+
+void
+ProvideLogFunction(LogFunction aLogFunction)
+{
+  sLogFunction = aLogFunction;
+}
+
+void
+LogBlocked(const char* aFunctionName, const char* aContext, uint32_t aFramesToSkip)
+{
+  if (sLogFunction) {
+    sLogFunction("BLOCKED", aFunctionName, aContext,
+                 /* aShouldLogStackTrace */ true, aFramesToSkip);
+  }
+}
+
+void
+LogBlocked(const char* aFunctionName, const wchar_t* aContext)
+{
+  if (sLogFunction) {
+    // Skip an extra frame to allow for this function.
+    LogBlocked(aFunctionName,  WideToUTF8(aContext).c_str(), /* aFramesToSkip */ 3);
+  }
+}
+
+void
+LogBlocked(const char* aFunctionName, const wchar_t* aContext,
+           uint16_t aLength)
+{
+  if (sLogFunction) {
+    // Skip an extra frame to allow for this function.
+    LogBlocked(aFunctionName, WideToUTF8(std::wstring(aContext, aLength)).c_str(),
+               /* aFramesToSkip */ 3);
+  }
+}
+
+void
+LogAllowed(const char* aFunctionName, const char* aContext)
+{
+  if (sLogFunction) {
+    sLogFunction("Broker ALLOWED", aFunctionName, aContext,
+                 /* aShouldLogStackTrace */ false, /* aFramesToSkip */ 0);
+  }
+}
+
+void
+LogAllowed(const char* aFunctionName, const wchar_t* aContext)
+{
+  if (sLogFunction) {
+    LogAllowed(aFunctionName, WideToUTF8(aContext).c_str());
+  }
+}
+
+void
+LogAllowed(const char* aFunctionName, const wchar_t* aContext,
+           uint16_t aLength)
+{
+  if (sLogFunction) {
+    LogAllowed(aFunctionName, WideToUTF8(std::wstring(aContext, aLength)).c_str());
+  }
+}
+
+} // warnonlysandbox
+} // mozilla
new file mode 100644
--- /dev/null
+++ b/security/sandbox/win/src/warnonlysandbox/warnOnlySandbox.h
@@ -0,0 +1,62 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * 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/. */
+
+/*
+ * Set of helper methods to implement a warn only sandbox.
+ * Only providing simple namespaced functions as this code will probably be
+ * removed once we are properly shipping the content sandbox.
+ */
+
+#ifndef security_sandbox_warnOnlySandbox_h__
+#define security_sandbox_warnOnlySandbox_h__
+
+#include "wosTypes.h"
+
+#ifdef SANDBOX_EXPORTS
+#define SANDBOX_EXPORT __declspec(dllexport)
+#else
+#define SANDBOX_EXPORT __declspec(dllimport)
+#endif
+
+namespace sandbox {
+class TargetPolicy;
+}
+
+namespace mozilla {
+namespace warnonlysandbox {
+
+// This is used to pass a LogCallback to the sandboxing code, as the logging
+// requires code to which we cannot link directly.
+void SANDBOX_EXPORT ProvideLogFunction(LogFunction aLogFunction);
+
+// Set up the sandbox to allow everything via the broker, so we can log calls.
+void ApplyWarnOnlyPolicy(sandbox::TargetPolicy& aPolicy);
+
+// Log a "BLOCKED" msg to the browser console and, if DEBUG build, stderr.
+// If the logging of a stack trace is enabled then the default aFramesToSkip
+// will start from our caller's caller, which should normally be the function
+// that triggered the interception.
+void LogBlocked(const char* aFunctionName, const char* aContext = nullptr,
+                uint32_t aFramesToSkip = 2);
+
+// Convenience functions to convert to char*.
+void LogBlocked(const char* aFunctionName, const wchar_t* aContext);
+void LogBlocked(const char* aFunctionName, const wchar_t* aContext,
+                uint16_t aLength);
+
+// Log a "ALLOWED" msg to the browser console and, if DEBUG build, stderr.
+void LogAllowed(const char* aFunctionName, const char* aContext = nullptr);
+
+// Convenience functions to convert to char*.
+void LogAllowed(const char* aFunctionName, const wchar_t* aContext);
+void LogAllowed(const char* aFunctionName, const wchar_t* aContext,
+                uint16_t aLength);
+
+
+} // warnonlysandbox
+} // mozilla
+
+#endif // security_sandbox_warnOnlySandbox_h__
new file mode 100644
--- /dev/null
+++ b/security/sandbox/win/src/warnonlysandbox/wosCallbacks.h
@@ -0,0 +1,129 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * 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/. */
+
+#ifndef security_sandbox_wosEnableCallbacks_h__
+#define security_sandbox_wosEnableCallbacks_h__
+
+#include "mozilla/warnonlysandbox/wosTypes.h"
+#include "mozilla/warnonlysandbox/warnOnlySandbox.h"
+
+#ifdef TARGET_SANDBOX_EXPORTS
+#include <sstream>
+#include <iostream>
+
+#include "mozilla/Preferences.h"
+#include "nsContentUtils.h"
+
+// This is essentially the same logic that decides whether nsStackWalk.cpp gets
+// built. See xpcom/base/moz.build
+#if !defined(MOZ_OPTIMIZE) || defined(MOZ_PROFILING) || defined(DEBUG)
+#define MOZ_STACKWALKING
+#include "nsStackWalk.h"
+#endif
+#endif
+
+#ifdef TARGET_SANDBOX_EXPORTS
+#define TARGET_SANDBOX_EXPORT __declspec(dllexport)
+#else
+#define TARGET_SANDBOX_EXPORT __declspec(dllimport)
+#endif
+
+namespace mozilla {
+namespace warnonlysandbox {
+
+// We need to use a callback to work around the fact that sandbox_s lib is
+// linked into plugin-container.exe directly and also via xul.dll via
+// sandboxbroker.dll. This causes problems with holding the state required to
+// work the warn only sandbox.
+// So, we provide a callback from plugin-container.exe that the code in xul.dll
+// can call to make sure we hit the right version of the code.
+void TARGET_SANDBOX_EXPORT
+SetProvideLogFunctionCb(ProvideLogFunctionCb aProvideLogFunctionCb);
+
+// Initialize the warn only sandbox if required.
+static void
+PrepareForInit()
+{
+  SetProvideLogFunctionCb(ProvideLogFunction);
+}
+
+#ifdef TARGET_SANDBOX_EXPORTS
+static ProvideLogFunctionCb sProvideLogFunctionCb = nullptr;
+
+void
+SetProvideLogFunctionCb(ProvideLogFunctionCb aProvideLogFunctionCb)
+{
+  sProvideLogFunctionCb = aProvideLogFunctionCb;
+}
+
+#ifdef MOZ_STACKWALKING
+static uint32_t sStackTraceDepth = 0;
+
+// NS_WalkStackCallback to write a formatted stack frame to an ostringstream.
+static void
+StackFrameToOStringStream(void* aPC, void* aSP, void* aClosure)
+{
+  std::ostringstream* stream = static_cast<std::ostringstream*>(aClosure);
+  nsCodeAddressDetails details;
+  char buf[1024];
+  NS_DescribeCodeAddress(aPC, &details);
+  NS_FormatCodeAddressDetails(aPC, &details, buf, sizeof(buf));
+  *stream << "--" << buf;
+}
+#endif
+
+// Log to the browser console and, if DEBUG build, stderr.
+static void
+Log(const char* aMessageType,
+    const char* aFunctionName,
+    const char* aContext,
+    const bool aShouldLogStackTrace = false,
+    uint32_t aFramesToSkip = 0)
+{
+  std::ostringstream msgStream;
+  msgStream << "Process Sandbox " << aMessageType << ": " << aFunctionName;
+  if (aContext) {
+    msgStream << " for : " << aContext;
+  }
+  msgStream << std::endl;
+
+#ifdef MOZ_STACKWALKING
+  if (aShouldLogStackTrace) {
+    if (sStackTraceDepth) {
+      msgStream << "Stack Trace:" << std::endl;
+      NS_StackWalk(StackFrameToOStringStream, aFramesToSkip, sStackTraceDepth,
+                   &msgStream, 0, nullptr);
+    }
+  }
+#endif
+
+  std::string msg = msgStream.str();
+#ifdef DEBUG
+  std::cerr << msg;
+#endif
+
+  nsContentUtils::LogMessageToConsole(msg.c_str());
+}
+
+// Initialize the warn only sandbox if required.
+static void
+InitIfRequired()
+{
+  if (XRE_GetProcessType() == GeckoProcessType_Content
+      && Preferences::GetString("browser.tabs.remote.sandbox").EqualsLiteral("warn")
+      && sProvideLogFunctionCb) {
+#ifdef MOZ_STACKWALKING
+    Preferences::AddUintVarCache(&sStackTraceDepth,
+      "browser.tabs.remote.sandbox.warnOnlyStackTraceDepth");
+#endif
+    sProvideLogFunctionCb(Log);
+  }
+}
+#endif
+} // warnonlysandbox
+} // mozilla
+
+#endif // security_sandbox_wosEnableCallbacks_h__
new file mode 100644
--- /dev/null
+++ b/security/sandbox/win/src/warnonlysandbox/wosTypes.h
@@ -0,0 +1,27 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * 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/. */
+
+#ifndef security_sandbox_wosTypes_h__
+#define security_sandbox_wosTypes_h__
+
+#include <stdint.h>
+
+namespace mozilla {
+namespace warnonlysandbox {
+
+// We are using callbacks here that are passed in from the core code to prevent
+// a circular dependency in the linking during the build.
+typedef void (*LogFunction) (const char* aMessageType,
+                             const char* aFunctionName,
+                             const char* aContext,
+                             const bool aShouldLogStackTrace,
+                             uint32_t aFramesToSkip);
+typedef void (*ProvideLogFunctionCb) (LogFunction aLogFunction);
+
+} // warnonlysandbox
+} // mozilla
+
+#endif // security_sandbox_wosTypes_h__
--- a/toolkit/xre/moz.build
+++ b/toolkit/xre/moz.build
@@ -163,8 +163,11 @@ if CONFIG['MOZ_ENABLE_XREMOTE']:
 if CONFIG['MOZ_B2G_LOADER']:
     DEFINES['OMNIJAR_NAME'] = CONFIG['OMNIJAR_NAME']
 CXXFLAGS += CONFIG['TK_CFLAGS']
 CXXFLAGS += CONFIG['MOZ_DBUS_CFLAGS']
 CXXFLAGS += CONFIG['MOZ_DBUS_GLIB_CFLAGS']
 
 if CONFIG['MOZ_WIDGET_GTK']:
     CXXFLAGS += CONFIG['MOZ_PANGO_CFLAGS']
+
+if CONFIG['MOZ_OPTIMIZE']:
+    DEFINES['MOZ_OPTIMIZE'] = True
--- a/toolkit/xre/nsEmbedFunctions.cpp
+++ b/toolkit/xre/nsEmbedFunctions.cpp
@@ -69,16 +69,21 @@
 
 #include "mozilla/ipc/TestShellParent.h"
 #include "mozilla/ipc/XPCShellEnvironment.h"
 
 #include "GMPProcessChild.h"
 
 #include "GeckoProfiler.h"
 
+#if defined(MOZ_CONTENT_SANDBOX) && defined(XP_WIN)
+#define TARGET_SANDBOX_EXPORTS
+#include "mozilla/warnonlysandbox/wosCallbacks.h"
+#endif
+
 #ifdef MOZ_IPDL_TESTS
 #include "mozilla/_ipdltest/IPDLUnitTests.h"
 #include "mozilla/_ipdltest/IPDLUnitTestProcessChild.h"
 
 using mozilla::_ipdltest::IPDLUnitTestProcessChild;
 #endif  // ifdef MOZ_IPDL_TESTS
 
 #ifdef MOZ_B2G_LOADER
@@ -530,16 +535,22 @@ XRE_InitChildProcess(int aArgc,
       }
 
       if (!process->Init()) {
         profiler_shutdown();
         NS_LogTerm();
         return NS_ERROR_FAILURE;
       }
 
+#if defined(MOZ_CONTENT_SANDBOX) && defined(XP_WIN)
+      // We need to do this after the process has been initialised, as
+      // InitIfRequired needs access to prefs.
+      mozilla::warnonlysandbox::InitIfRequired();
+#endif
+
       // Run the UI event loop on the main thread.
       uiMessageLoop.MessageLoop::Run();
 
       // Allow ProcessChild to clean up after itself before going out of
       // scope and being deleted
       process->CleanUp();
       mozilla::Omnijar::CleanUp();
     }