Bug 1495983: Assert system privileged about: pages have CSP. r=smaug
authorChristoph Kerschbaumer <ckerschb@christophkerschbaumer.com>
Wed, 03 Oct 2018 09:47:08 +0200
changeset 495350 37fcdbb6756c61ca4d626999d6d5447bfe631555
parent 495349 6af3691ec0d1747ff384c8a61fee44918323e773
child 495351 cf579f097fff49b756b8888fa7812c500796cd96
push id9984
push userffxbld-merge
push dateMon, 15 Oct 2018 21:07:35 +0000
treeherdermozilla-beta@183d27ea8570 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs1495983
milestone64.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 1495983: Assert system privileged about: pages have CSP. r=smaug
browser/base/content/test/general/browser_e10s_about_page_triggeringprincipal.js
browser/components/sessionstore/test/browser_parentProcessRestoreHash.js
dom/base/nsDocument.cpp
dom/security/test/general/test_assert_about_page_no_csp.html
modules/libpref/init/all.js
--- a/browser/base/content/test/general/browser_e10s_about_page_triggeringprincipal.js
+++ b/browser/base/content/test/general/browser_e10s_about_page_triggeringprincipal.js
@@ -9,16 +9,19 @@ const kAboutPagesRegistered = Promise.al
     Ci.nsIAboutModule.URI_MUST_LOAD_IN_CHILD | Ci.nsIAboutModule.ALLOW_SCRIPT),
   BrowserTestUtils.registerAboutPage(
     registerCleanupFunction, "test-about-principal-parent", kParentPage,
     Ci.nsIAboutModule.ALLOW_SCRIPT),
 ]);
 
 add_task(async function test_principal_click() {
   await kAboutPagesRegistered;
+  await SpecialPowers.pushPrefEnv({
+    "set": [["csp.skip_about_page_has_csp_assert", true]],
+  });
   await BrowserTestUtils.withNewTab("about:test-about-principal-parent", async function(browser) {
     let loadPromise = BrowserTestUtils.browserLoaded(browser, false, "about:test-about-principal-child");
     let myLink = browser.contentDocument.getElementById("aboutchildprincipal");
     myLink.click();
     await loadPromise;
 
     await ContentTask.spawn(gBrowser.selectedBrowser, {}, async function() {
       let channel = content.docShell.currentDocumentChannel;
@@ -39,17 +42,17 @@ add_task(async function test_principal_c
          "sanity check - load of TYPE_DOCUMENT must have a null loadingPrincipal");
     });
   });
 });
 
 add_task(async function test_principal_ctrl_click() {
   await kAboutPagesRegistered;
   await SpecialPowers.pushPrefEnv({
-    "set": [["security.sandbox.content.level", 1]],
+    "set": [["security.sandbox.content.level", 1], ["csp.skip_about_page_has_csp_assert", true]],
   });
 
   await BrowserTestUtils.withNewTab("about:test-about-principal-parent", async function(browser) {
     let loadPromise = BrowserTestUtils.waitForNewTab(gBrowser, "about:test-about-principal-child");
     // simulate ctrl+click
     BrowserTestUtils.synthesizeMouseAtCenter("#aboutchildprincipal",
                                              { ctrlKey: true, metaKey: true },
                                              gBrowser.selectedBrowser);
@@ -76,17 +79,17 @@ add_task(async function test_principal_c
     });
     BrowserTestUtils.removeTab(tab);
   });
 });
 
 add_task(async function test_principal_right_click_open_link_in_new_tab() {
   await kAboutPagesRegistered;
   await SpecialPowers.pushPrefEnv({
-    "set": [["security.sandbox.content.level", 1]],
+    "set": [["security.sandbox.content.level", 1], ["csp.skip_about_page_has_csp_assert", true]],
   });
 
   await BrowserTestUtils.withNewTab("about:test-about-principal-parent", async function(browser) {
     let loadPromise = BrowserTestUtils.waitForNewTab(gBrowser, "about:test-about-principal-child");
 
     // simulate right-click open link in tab
     BrowserTestUtils.waitForEvent(document, "popupshown", false, event => {
       // These are operations that must be executed synchronously with the event.
--- a/browser/components/sessionstore/test/browser_parentProcessRestoreHash.js
+++ b/browser/components/sessionstore/test/browser_parentProcessRestoreHash.js
@@ -49,16 +49,18 @@ let TestAboutPage = {
 };
 
 
 /**
  * Test that switching from a remote to a parent process browser
  * correctly clears the userTypedValue
  */
 add_task(async function() {
+  await SpecialPowers.pushPrefEnv({set: [["csp.skip_about_page_has_csp_assert", true]]});
+
   TestAboutPage.register();
   let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, "http://example.com/", true, true);
   ok(tab.linkedBrowser.isRemoteBrowser, "Browser should be remote");
 
   let resolveLocationChangePromise;
   let locationChangePromise = new Promise(r => resolveLocationChangePromise = r);
   let wpl = {
     onStateChange(listener, request, state, status) {
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -5303,68 +5303,50 @@ nsIDocument::DispatchContentLoadedEvents
 // attached, but ultimately that whitelist should disappear.
 // Please note that any about: page should not use inline JS or inline CSS,
 // and instead should load JS and CSS from an external file (*.js, *.css)
 // which allows us to apply a strong CSP omitting 'unsafe-inline'. Ideally,
 // the CSP allows precisely the resources that need to be loaded; but it
 // should at least be as strong as:
 // <meta http-equiv="Content-Security-Policy" content="default-src chrome:"/>
 static void
-AssertContentPrivilegedAboutPageHasCSP(nsIURI* aDocumentURI, nsIPrincipal* aPrincipal)
-{
-  // Curently we can't serialize the CSP, hence we only assert if
-  // running in the content process.
-  if (!XRE_IsContentProcess()) {
-    return;
-  }
-
+AssertAboutPageHasCSP(nsIURI* aDocumentURI, nsIPrincipal* aPrincipal)
+{
   // Check if we are loading an about: URI at all
   bool isAboutURI =
     (NS_SUCCEEDED(aDocumentURI->SchemeIs("about", &isAboutURI)) && isAboutURI);
 
-  if (!isAboutURI) {
-    return;
-  }
-
-  // Check if we are loading a content-privileged about: URI
-  nsCOMPtr<nsIAboutModule> aboutModule;
-  nsresult rv = NS_GetAboutModule(aDocumentURI, getter_AddRefs(aboutModule));
-  NS_ENSURE_SUCCESS_VOID(rv);
-
-  uint32_t aboutModuleFlags = 0;
-  rv = aboutModule->GetURIFlags(aDocumentURI, &aboutModuleFlags);
-  NS_ENSURE_SUCCESS_VOID(rv);
-
-  if (!(aboutModuleFlags & nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT)) {
+  if (!isAboutURI || Preferences::GetBool("csp.skip_about_page_has_csp_assert")) {
     return;
   }
 
   // Potentially init the legacy whitelist of about URIs without a CSP.
   static StaticAutoPtr<nsTArray<nsCString>> sLegacyAboutPagesWithNoCSP;
   if (!sLegacyAboutPagesWithNoCSP ||
-      Preferences::GetBool("csp.overrule_content_privileged_about_uris_without_csp_whitelist")) {
+      Preferences::GetBool("csp.overrule_about_uris_without_csp_whitelist")) {
     sLegacyAboutPagesWithNoCSP = new nsTArray<nsCString>();
     nsAutoCString legacyAboutPages;
-    Preferences::GetCString("csp.content_privileged_about_uris_without_csp",
+    Preferences::GetCString("csp.about_uris_without_csp",
       legacyAboutPages);
     for (const nsACString& hostString : legacyAboutPages.Split(',')) {
       // please note that for the actual whitelist we only store the path of
       // about: URI. Let's reassemble the full about URI here so we don't
       // have to remove query arguments later.
       nsCString aboutURI;
       aboutURI.AppendLiteral("about:");
       aboutURI.Append(hostString);
       sLegacyAboutPagesWithNoCSP->AppendElement(aboutURI);
     }
     ClearOnShutdown(&sLegacyAboutPagesWithNoCSP);
   }
 
   // Check if the about URI is whitelisted
   nsAutoCString aboutSpec;
   aDocumentURI->GetSpec(aboutSpec);
+  ToLowerCase(aboutSpec);
   for (auto& legacyPageEntry : *sLegacyAboutPagesWithNoCSP) {
     // please note that we perform a substring match here on purpose,
     // so we don't have to deal and parse out all the query arguments
     // the various about pages rely on.
     if (aboutSpec.Find(legacyPageEntry) == 0) {
       return;
     }
   }
@@ -5374,32 +5356,32 @@ AssertContentPrivilegedAboutPageHasCSP(n
   nsAutoString parsedPolicyStr;
   if (csp) {
     uint32_t policyCount = 0;
      csp->GetPolicyCount(&policyCount);
      if (policyCount > 0) {
        csp->GetPolicyString(0, parsedPolicyStr);
      }
   }
-  if (Preferences::GetBool("csp.overrule_content_privileged_about_uris_without_csp_whitelist")) {
+  if (Preferences::GetBool("csp.overrule_about_uris_without_csp_whitelist")) {
     NS_ASSERTION(parsedPolicyStr.Find("default-src") >= 0, "about: page must have a CSP");
     return;
   }
   MOZ_ASSERT(parsedPolicyStr.Find("default-src") >= 0,
     "about: page must contain a CSP including default-src");
 }
 #endif
 
 void
 nsDocument::EndLoad()
 {
 #if defined(DEBUG) && !defined(ANDROID)
   // only assert if nothing stopped the load on purpose
   if (!mParserAborted) {
-    AssertContentPrivilegedAboutPageHasCSP(mDocumentURI, NodePrincipal());
+    AssertAboutPageHasCSP(mDocumentURI, NodePrincipal());
   }
 #endif
 
   // EndLoad may have been called without a matching call to BeginLoad, in the
   // case of a failed parse (for example, due to timeout). In such a case, we
   // still want to execute part of this code to do appropriate cleanup, but we
   // gate part of it because it is intended to match 1-for-1 with calls to
   // BeginLoad. We have an explicit flag bit for this purpose, since it's
--- a/dom/security/test/general/test_assert_about_page_no_csp.html
+++ b/dom/security/test/general/test_assert_about_page_no_csp.html
@@ -9,33 +9,33 @@
 <iframe id="testframe"></iframe>
 <script class="testbody" type="text/javascript">
 
   SimpleTest.waitForExplicitFinish();
   SimpleTest.expectAssertions(0, 1);
 
   // Test Setup:
   // The test overrules the whitelist of about: pages that are allowed to load without a CSP
-  // and makes sure to hit the assertion within AssertContentPrivilegedAboutPageHasCSP().
-  // However, due to the caching mechanism within AssertContentPrivilegedAboutPageHasCSP this
+  // and makes sure to hit the assertion within AssertAboutPageHasCSP().
+  // However, due to the caching mechanism within AssertAboutPageHasCSP this
   // test loads a second dummy data: URI to reset the old cache and finally resets the pref
   // used for testing purposes.
 
-  let origWhiteList = SpecialPowers.getCharPref("csp.content_privileged_about_uris_without_csp");
+  let origWhiteList = SpecialPowers.getCharPref("csp.about_uris_without_csp");
 
-  SpecialPowers.setCharPref("csp.content_privileged_about_uris_without_csp", "");
-  SpecialPowers.setBoolPref("csp.overrule_content_privileged_about_uris_without_csp_whitelist", true);
+  SpecialPowers.setCharPref("csp.about_uris_without_csp", "");
+  SpecialPowers.setBoolPref("csp.overrule_about_uris_without_csp_whitelist", true);
 
   ok(true, "sanity: prefs flipped and test runs");
   let myFrame = document.getElementById("testframe");
   myFrame.src = "about:blank";
   // booom :-)
 
-  SpecialPowers.setCharPref("csp.content_privileged_about_uris_without_csp", origWhiteList);
+  SpecialPowers.setCharPref("csp.about_uris_without_csp", origWhiteList);
   myFrame.src = "data:text/html,<body>just a dumy data: URI</body>";
 
-  SpecialPowers.setBoolPref("csp.overrule_content_privileged_about_uris_without_csp_whitelist", false);
+  SpecialPowers.setBoolPref("csp.overrule_about_uris_without_csp_whitelist", false);
 
   SimpleTest.finish();
 </script>
 </pre>
 </body>
 </html>
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -2591,19 +2591,20 @@ pref("font.blacklist.underline_offset", 
 
 pref("security.directory",              "");
 
 // security-sensitive dialogs should delay button enabling. In milliseconds.
 pref("security.dialog_enable_delay", 1000);
 pref("security.notification_enable_delay", 500);
 
 #if defined(DEBUG) && !defined(ANDROID)
-pref("csp.content_privileged_about_uris_without_csp", "blank,printpreview,srcdoc");
-// the following pref is for testing purposes only.
-pref("csp.overrule_content_privileged_about_uris_without_csp_whitelist", false);
+pref("csp.about_uris_without_csp", "blank,printpreview,srcdoc,about,addons,cache-entry,config,crashes,debugging,devtools,downloads,home,memory,networking,newtab,performance,plugins,policies,profiles,restartrequired,searchreset,serviceworkers,sessionrestore,support,sync-log,telemetry,url-classifier,webrtc,welcomeback");
+// the following prefs are for testing purposes only.
+pref("csp.overrule_about_uris_without_csp_whitelist", false);
+pref("csp.skip_about_page_has_csp_assert", false);
 #endif
 
 // Default Content Security Policy to apply to signed contents.
 pref("security.signed_content.CSP.default", "script-src 'self'; style-src 'self'");
 
 // Mixed content blocking
 pref("security.mixed_content.block_active_content", false);
 pref("security.mixed_content.block_display_content", false);