Bug 1515863, r=ckerschb
authorGijs Kruitbosch <gijskruitbosch@gmail.com>
Tue, 08 Jan 2019 16:59:21 +0100
changeset 510148 8686beefb44f25a78bb91bc6d5a9e5582f9ffa9a
parent 510147 25334f588aa4b005e7a96d975dd14831fb738a24
child 510149 29b2c2f578797279a9d55764da73158136081d89
child 510176 af06731b5203d12428e0e17d2ad8fc9302d93277
push id10547
push userffxbld-merge
push dateMon, 21 Jan 2019 13:03:58 +0000
treeherdermozilla-beta@24ec1916bffe [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersckerschb
bugs1515863
milestone66.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 1515863, r=ckerschb Differential Revision: https://phabricator.services.mozilla.com/D15957
caps/BasePrincipal.cpp
docshell/test/browser/browser.ini
docshell/test/browser/browser_data_load_inherit_csp.js
docshell/test/browser/file_data_load_inherit_csp.html
dom/security/nsCSPContext.cpp
dom/security/nsCSPContext.h
--- a/caps/BasePrincipal.cpp
+++ b/caps/BasePrincipal.cpp
@@ -18,16 +18,17 @@
 #include "nsScriptSecurityManager.h"
 #include "nsServiceManagerUtils.h"
 
 #include "mozilla/ContentPrincipal.h"
 #include "mozilla/NullPrincipal.h"
 #include "mozilla/dom/BlobURLProtocolHandler.h"
 #include "mozilla/dom/ChromeUtils.h"
 #include "mozilla/dom/CSPDictionariesBinding.h"
+#include "mozilla/dom/nsCSPContext.h"
 #include "mozilla/dom/ToJSValue.h"
 
 namespace mozilla {
 
 BasePrincipal::BasePrincipal(PrincipalKind aKind)
     : mKind(aKind), mHasExplicitDomain(false), mInitialized(false) {}
 
 BasePrincipal::~BasePrincipal() {}
@@ -501,18 +502,30 @@ void BasePrincipal::FinishInit(BasePrinc
 
   // First compute the origin suffix since it's infallible.
   nsAutoCString originSuffix;
   mOriginAttributes.CreateSuffix(originSuffix);
   mOriginSuffix = NS_Atomize(originSuffix);
 
   mOriginNoSuffix = aOther->mOriginNoSuffix;
   mHasExplicitDomain = aOther->mHasExplicitDomain;
-  mCSP = aOther->mCSP;
-  mPreloadCSP = aOther->mPreloadCSP;
+
+  if (aOther->mPreloadCSP) {
+    mPreloadCSP = do_CreateInstance("@mozilla.org/cspcontext;1");
+    nsCSPContext* preloadCSP = static_cast<nsCSPContext*>(mPreloadCSP.get());
+    preloadCSP->InitFromOther(
+        static_cast<nsCSPContext*>(aOther->mPreloadCSP.get()), nullptr, this);
+  }
+
+  if (aOther->mCSP) {
+    mCSP = do_CreateInstance("@mozilla.org/cspcontext;1");
+    nsCSPContext* csp = static_cast<nsCSPContext*>(mCSP.get());
+    csp->InitFromOther(static_cast<nsCSPContext*>(aOther->mCSP.get()), nullptr,
+                       this);
+  }
 }
 
 bool SiteIdentifier::Equals(const SiteIdentifier& aOther) const {
   MOZ_ASSERT(IsInitialized());
   MOZ_ASSERT(aOther.IsInitialized());
   return mPrincipal->FastEquals(aOther.mPrincipal);
 }
 
--- a/docshell/test/browser/browser.ini
+++ b/docshell/test/browser/browser.ini
@@ -49,16 +49,17 @@ support-files =
   test-form_sjis.html
   timelineMarkers-04.html
   browser_timelineMarkers-frame-02.js
   browser_timelineMarkers-frame-03.js
   browser_timelineMarkers-frame-04.js
   browser_timelineMarkers-frame-05.js
   head.js
   frame-head.js
+  file_data_load_inherit_csp.html
   file_click_link_within_view_source.html
   onload_message.html
   onpageshow_message.html
 
 [browser_bug1206879.js]
 [browser_bug1309900_crossProcessHistoryNavigation.js]
 [browser_bug1328501.js]
 [browser_bug1347823.js]
@@ -87,16 +88,17 @@ skip-if = verify
 [browser_bug554155.js]
 [browser_bug655270.js]
 [browser_bug655273.js]
 [browser_bug670318.js]
 [browser_bug673467.js]
 [browser_bug852909.js]
 skip-if = (verify && debug && (os == 'win'))
 [browser_bug92473.js]
+[browser_data_load_inherit_csp.js]
 [browser_dataURI_unique_opaque_origin.js]
 [browser_uriFixupIntegration.js]
 [browser_uriFixupAlternateRedirects.js]
 support-files =
   redirect_to_example.sjs
 [browser_loadDisallowInherit.js]
 [browser_loadURI.js]
 skip-if = (verify && !debug && os == 'mac') || (os == 'linux') || (os == 'mac') # Bug 1423959
new file mode 100644
--- /dev/null
+++ b/docshell/test/browser/browser_data_load_inherit_csp.js
@@ -0,0 +1,82 @@
+"use strict";
+
+const TEST_PATH = getRootDirectory(gTestPath).replace("chrome://mochitests/content", "http://example.com");
+const HTML_URI = TEST_PATH + "file_data_load_inherit_csp.html";
+const DATA_URI = "data:text/html;html,<html><body>foo</body></html>";
+
+function setDataHrefOnLink(aBrowser, aDataURI) {
+  return ContentTask.spawn(aBrowser, aDataURI, function(uri) {
+    let link = content.document.getElementById("testlink");
+    link.href = uri;
+  });
+};
+
+function verifyCSP(aTestName, aBrowser, aDataURI) {
+  return ContentTask.spawn(aBrowser, {aTestName, aDataURI}, async function ({aTestName, aDataURI}) {
+    let channel = content.docShell.currentDocumentChannel;
+    is(channel.URI.spec, aDataURI, "testing CSP for " + aTestName);
+    let principal = channel.loadInfo.triggeringPrincipal;
+    let cspJSON = principal.cspJSON;
+    let cspOBJ = JSON.parse(cspJSON);
+    let policies = cspOBJ["csp-policies"];
+    is(policies.length, 1, "should be one policy");
+    let policy = policies[0];
+    is(policy['script-src'], "'unsafe-inline'", "script-src directive matches");
+  });
+};
+
+add_task(async function setup() {
+  // allow top level data: URI navigations, otherwise clicking data: link fails
+  await SpecialPowers.pushPrefEnv({
+    "set": [["security.data_uri.block_toplevel_data_uri_navigations", false]],
+  });
+});
+
+add_task(async function test_data_csp_inheritance_regular_click() {
+  await BrowserTestUtils.withNewTab(HTML_URI, async function(browser) {
+    let loadPromise = BrowserTestUtils.browserLoaded(browser, false, DATA_URI);
+    // set the data href + simulate click
+    await setDataHrefOnLink(gBrowser.selectedBrowser, DATA_URI);
+    BrowserTestUtils.synthesizeMouseAtCenter("#testlink", {},
+                                             gBrowser.selectedBrowser);
+    await loadPromise;
+    await verifyCSP("click()", gBrowser.selectedBrowser, DATA_URI);
+  });
+});
+
+add_task(async function test_data_csp_inheritance_ctrl_click() {
+  await BrowserTestUtils.withNewTab(HTML_URI, async function(browser) {
+    let loadPromise = BrowserTestUtils.waitForNewTab(gBrowser, DATA_URI);
+    // set the data href + simulate ctrl+click
+    await setDataHrefOnLink(gBrowser.selectedBrowser, DATA_URI);
+    BrowserTestUtils.synthesizeMouseAtCenter("#testlink",
+                                             { ctrlKey: true, metaKey: true },
+                                             gBrowser.selectedBrowser);
+    let tab = await loadPromise;
+    gBrowser.selectTabAtIndex(2);
+    await verifyCSP("ctrl-click()", gBrowser.selectedBrowser, DATA_URI);
+    await BrowserTestUtils.removeTab(tab);
+  });
+});
+
+add_task(async function test_data_csp_inheritance_right_click_open_link_in_new_tab() {
+  await BrowserTestUtils.withNewTab(HTML_URI, async function(browser) {
+    let loadPromise = BrowserTestUtils.waitForNewTab(gBrowser, DATA_URI);
+    // set the data href + simulate right-click open link in tab
+    await setDataHrefOnLink(gBrowser.selectedBrowser, DATA_URI);
+    BrowserTestUtils.waitForEvent(document, "popupshown", false, event => {
+      // These are operations that must be executed synchronously with the event.
+      document.getElementById("context-openlinkintab").doCommand();
+      event.target.hidePopup();
+      return true;
+    });
+    BrowserTestUtils.synthesizeMouseAtCenter("#testlink",
+                                             { type: "contextmenu", button: 2 },
+                                             gBrowser.selectedBrowser);
+
+    let tab = await loadPromise;
+    gBrowser.selectTabAtIndex(2);
+    await verifyCSP("right-click-open-in-new-tab()", gBrowser.selectedBrowser, DATA_URI);
+    await BrowserTestUtils.removeTab(tab);
+  });
+});
new file mode 100644
--- /dev/null
+++ b/docshell/test/browser/file_data_load_inherit_csp.html
@@ -0,0 +1,11 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <meta charset="utf-8">
+  <title>Bug 1358009 - Inherit CSP into data URI</title>
+  <meta http-equiv="Content-Security-Policy" content="script-src 'unsafe-inline'">
+</head>
+<body>
+  <a id="testlink">testlink</a>
+</body>
+</html>
--- a/dom/security/nsCSPContext.cpp
+++ b/dom/security/nsCSPContext.cpp
@@ -256,16 +256,32 @@ nsCSPContext::nsCSPContext()
 
 nsCSPContext::~nsCSPContext() {
   CSPCONTEXTLOG(("nsCSPContext::~nsCSPContext"));
   for (uint32_t i = 0; i < mPolicies.Length(); i++) {
     delete mPolicies[i];
   }
 }
 
+nsresult nsCSPContext::InitFromOther(nsCSPContext* aOtherContext,
+                                     Document* aDoc, nsIPrincipal* aPrincipal) {
+  NS_ENSURE_ARG(aOtherContext);
+
+  nsresult rv = SetRequestContext(aDoc, aPrincipal);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  for (auto policy : aOtherContext->mPolicies) {
+    nsAutoString policyStr;
+    policy->toString(policyStr);
+    AppendPolicy(policyStr, policy->getReportOnlyFlag(),
+                 policy->getDeliveredViaMetaTagFlag());
+  }
+  return NS_OK;
+}
+
 NS_IMETHODIMP
 nsCSPContext::GetPolicyString(uint32_t aIndex, nsAString& outStr) {
   outStr.Truncate();
   if (aIndex >= mPolicies.Length()) {
     return NS_ERROR_ILLEGAL_VALUE;
   }
   mPolicies[aIndex]->toString(outStr);
   return NS_OK;
--- a/dom/security/nsCSPContext.h
+++ b/dom/security/nsCSPContext.h
@@ -46,16 +46,20 @@ class nsCSPContext : public nsIContentSe
   NS_DECL_NSISERIALIZABLE
 
  protected:
   virtual ~nsCSPContext();
 
  public:
   nsCSPContext();
 
+  nsresult InitFromOther(nsCSPContext* otherContext,
+                         mozilla::dom::Document* aDoc,
+                         nsIPrincipal* aPrincipal);
+
   /**
    * SetRequestContext() needs to be called before the innerWindowID
    * is initialized on the document. Use this function to call back to
    * flush queued up console messages and initalize the innerWindowID.
    */
   void flushConsoleMessages();
 
   void logToConsole(const char* aName, const char16_t** aParams,