aboutsummaryrefslogblamecommitdiff
path: root/www/waterfox/files/patch-bug1381761
blob: 416bd4ac8c26e9ab65e547a32b0814a227e530a8 (plain) (tree)









































































































































































































































































































































































                                                                                                                                                                                                               
commit 256e249566d8
Author: Christoph Kerschbaumer <ckerschb@christophkerschbaumer.com>
Date:   Fri Aug 4 14:11:17 2017 +0200

    Bug 1381761 - Treating 'data:' documents as unique, opaque origins should still inherit the CSP. r=smaug,dveditz
---
 caps/moz.build                   |  1 +
 caps/nsScriptSecurityManager.cpp | 96 +++++++++++++++++++++++++---------------
 2 files changed, 62 insertions(+), 35 deletions(-)

diff --git caps/moz.build caps/moz.build
index 46331e93f097..af369e3268e0 100644
--- caps/moz.build
+++ caps/moz.build
@@ -56,6 +56,7 @@ LOCAL_INCLUDES += [
     '/docshell/base',
     '/dom/base',
     '/js/xpconnect/src',
+    '/netwerk/base',
 ]
 
 if CONFIG['ENABLE_TESTS']:
diff --git caps/nsScriptSecurityManager.cpp caps/nsScriptSecurityManager.cpp
index a930b324a6a2..90695ebd126f 100644
--- caps/nsScriptSecurityManager.cpp
+++ caps/nsScriptSecurityManager.cpp
@@ -45,6 +45,7 @@
 #include "nsIWindowWatcher.h"
 #include "nsIConsoleService.h"
 #include "nsIObserverService.h"
+#include "nsIOService.h"
 #include "nsIContent.h"
 #include "nsDOMJSUtils.h"
 #include "nsAboutProtocolUtils.h"
@@ -265,6 +266,61 @@ nsScriptSecurityManager::GetChannelResultPrincipalIfNotSandboxed(nsIChannel* aCh
                                    /*aIgnoreSandboxing*/ true);
 }
 
+static void
+InheritAndSetCSPOnPrincipalIfNeeded(nsIChannel* aChannel, nsIPrincipal* aPrincipal)
+{
+  // loading a data: URI into an iframe, or loading frame[srcdoc] need
+  // to inherit the CSP (see Bug 1073952, 1381761).
+  MOZ_ASSERT(aChannel && aPrincipal, "need a valid channel and principal");
+  if (!aChannel) {
+    return;
+  }
+
+  nsCOMPtr<nsILoadInfo> loadInfo = aChannel->GetLoadInfo();
+  if (!loadInfo ||
+      loadInfo->GetExternalContentPolicyType() != nsIContentPolicy::TYPE_SUBDOCUMENT) {
+    return;
+  }
+
+  nsCOMPtr<nsIURI> uri;
+  nsresult rv = aChannel->GetURI(getter_AddRefs(uri));
+  NS_ENSURE_SUCCESS_VOID(rv);
+  nsAutoCString URISpec;
+  rv = uri->GetSpec(URISpec);
+  NS_ENSURE_SUCCESS_VOID(rv);
+
+  bool isSrcDoc = URISpec.EqualsLiteral("about:srcdoc");
+  bool isData = (NS_SUCCEEDED(uri->SchemeIs("data", &isData)) && isData);
+
+  if (!isSrcDoc && !isData) {
+    return;
+  }
+
+  nsCOMPtr<nsIPrincipal> principalToInherit = loadInfo->PrincipalToInherit();
+  if (!principalToInherit) {
+    principalToInherit = loadInfo->TriggeringPrincipal();
+  }
+  nsCOMPtr<nsIContentSecurityPolicy> originalCSP;
+  principalToInherit->GetCsp(getter_AddRefs(originalCSP));
+  if (!originalCSP) {
+    return;
+  }
+
+  // if the principalToInherit had a CSP, add it to the before
+  // created NullPrincipal (unless it already has one)
+  MOZ_ASSERT(aPrincipal->GetIsNullPrincipal(),
+             "inheriting the CSP only valid for NullPrincipal");
+  nsCOMPtr<nsIContentSecurityPolicy> nullPrincipalCSP;
+  aPrincipal->GetCsp(getter_AddRefs(nullPrincipalCSP));
+  if (nullPrincipalCSP) {
+    MOZ_ASSERT(nullPrincipalCSP == originalCSP,
+               "There should be no other CSP here.");
+    // CSPs are equal, no need to set it again.
+    return;
+  }
+  aPrincipal->SetCsp(originalCSP);
+}
+
 nsresult
 nsScriptSecurityManager::GetChannelResultPrincipal(nsIChannel* aChannel,
                                                    nsIPrincipal** aPrincipal,
@@ -295,40 +351,7 @@ nsScriptSecurityManager::GetChannelResultPrincipal(nsIChannel* aChannel,
         if (!aIgnoreSandboxing && loadInfo->GetLoadingSandboxed()) {
           MOZ_ALWAYS_TRUE(NS_SUCCEEDED(loadInfo->GetSandboxedLoadingPrincipal(aPrincipal)));
           MOZ_ASSERT(*aPrincipal);
-            // if the new NullPrincipal (above) loads an iframe[srcdoc], we
-            // need to inherit an existing CSP to avoid bypasses (bug 1073952).
-            // We continue inheriting for nested frames with e.g., data: URLs.
-            if (loadInfo->GetExternalContentPolicyType() == nsIContentPolicy::TYPE_SUBDOCUMENT) {
-              nsCOMPtr<nsIURI> uri;
-              aChannel->GetURI(getter_AddRefs(uri));
-              nsAutoCString URISpec;
-              uri->GetSpec(URISpec);
-              bool isData = (NS_SUCCEEDED(uri->SchemeIs("data", &isData)) && isData);
-              if (URISpec.EqualsLiteral("about:srcdoc") || isData) {
-                nsCOMPtr<nsIPrincipal> principalToInherit = loadInfo->PrincipalToInherit();
-                if (!principalToInherit) {
-                  principalToInherit = loadInfo->TriggeringPrincipal();
-                }
-                nsCOMPtr<nsIContentSecurityPolicy> originalCSP;
-                principalToInherit->GetCsp(getter_AddRefs(originalCSP));
-                if (originalCSP) {
-                  // if the principalToInherit had a CSP,
-                  // add it to the newly created NullPrincipal
-                  // (unless it already has one)
-                  nsCOMPtr<nsIContentSecurityPolicy> nullPrincipalCSP;
-                  (*aPrincipal)->GetCsp(getter_AddRefs(nullPrincipalCSP));
-                  if (nullPrincipalCSP) {
-                    MOZ_ASSERT(nullPrincipalCSP == originalCSP,
-                              "There should be no other CSP here.");
-                    // CSPs are equal, no need to set it again.
-                    return NS_OK;
-                  } else {
-                    nsresult rv = (*aPrincipal)->SetCsp(originalCSP);
-                    NS_ENSURE_SUCCESS(rv, rv);
-                  }
-                }
-              }
-            }
+          InheritAndSetCSPOnPrincipalIfNeeded(aChannel, *aPrincipal);
           return NS_OK;
         }
 
@@ -376,7 +399,10 @@ nsScriptSecurityManager::GetChannelResultPrincipal(nsIChannel* aChannel,
       }
     }
   }
-  return GetChannelURIPrincipal(aChannel, aPrincipal);
+  nsresult rv = GetChannelURIPrincipal(aChannel, aPrincipal);
+  NS_ENSURE_SUCCESS(rv, rv);
+  InheritAndSetCSPOnPrincipalIfNeeded(aChannel, *aPrincipal);
+  return NS_OK;
 }
 
 /* The principal of the URI that this channel is loading. This is never

commit 9427f1bbd826
Author: Christoph Kerschbaumer <ckerschb@christophkerschbaumer.com>
Date:   Fri Aug 4 14:10:21 2017 +0200

    Bug 1381761 - Convert test browser_911547.js to comply with new data: URI inheritance model. r=dveditz
---
 .../components/sessionstore/test/browser_911547.js | 47 ++++++++++++++++------
 .../sessionstore/test/browser_911547_sample.html   |  6 +--
 2 files changed, 37 insertions(+), 16 deletions(-)

diff --git browser/components/sessionstore/test/browser_911547.js browser/components/sessionstore/test/browser_911547.js
index f0da70ed8f8c..cb95ddad7f2a 100644
--- browser/components/sessionstore/test/browser_911547.js
+++ browser/components/sessionstore/test/browser_911547.js
@@ -1,11 +1,17 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
-// This tests that session restore component does restore the right content
-// security policy with the document.
-// The policy being tested disallows inline scripts
+// This test is two fold:
+// a) if security.data_uri.unique_opaque_origin == false, then
+//    this tests that session restore component does restore the right
+//    content security policy with the document. (The policy being
+//    tested disallows inline scripts).
+// b) if security.data_uri.unique_opaque_origin == true, then
+//    this tests that data: URIs do not inherit the CSP from
+//    it's enclosing context.
 
 add_task(async function test() {
+  let dataURIPref = Services.prefs.getBoolPref("security.data_uri.unique_opaque_origin");
   // create a tab that has a CSP
   let testURL = "http://mochi.test:8888/browser/browser/components/sessionstore/test/browser_911547_sample.html";
   let tab = gBrowser.selectedTab = BrowserTestUtils.addTab(gBrowser, testURL);
@@ -16,23 +22,33 @@ add_task(async function test() {
 
   // this is a baseline to ensure CSP is active
   // attempt to inject and run a script via inline (pre-restore, allowed)
-  await injectInlineScript(browser, `document.getElementById("test_id").value = "fail";`);
+  await injectInlineScript(browser, `document.getElementById("test_id1").value = "id1_modified";`);
 
   let loadedPromise = promiseBrowserLoaded(browser);
   await ContentTask.spawn(browser, null, function() {
-    is(content.document.getElementById("test_id").value, "ok",
+    is(content.document.getElementById("test_id1").value, "id1_initial",
        "CSP should block the inline script that modifies test_id");
 
-    // attempt to click a link to a data: URI (will inherit the CSP of the
-    // origin document) and navigate to the data URI in the link.
+
+    // (a) if security.data_uri.unique_opaque_origin == false:
+    //     attempt to click a link to a data: URI (will inherit the CSP of
+    //     the origin document) and navigate to the data URI in the link.
+    // (b) if security.data_uri.unique_opaque_origin == true:
+    //     attempt to click a link to a data: URI (will *not* inherit the CSP of
+    //     the origin document) and navigate to the data URI in the link.
     content.document.getElementById("test_data_link").click();
   });
 
   await loadedPromise;
 
-  await ContentTask.spawn(browser, null, function() {
-    is(content.document.getElementById("test_id2").value, "ok",
-       "CSP should block the script loaded by the clicked data URI");
+  await ContentTask.spawn(browser, {dataURIPref}, function( {dataURIPref}) { // eslint-disable-line
+    if (dataURIPref) {
+      is(content.document.getElementById("test_id2").value, "id2_modified",
+         "data: URI should *not* inherit the CSP of the enclosing context");
+    } else {
+      is(content.document.getElementById("test_id2").value, "id2_initial",
+        "CSP should block the script loaded by the clicked data URI");
+    }
   });
 
   // close the tab
@@ -43,9 +59,14 @@ add_task(async function test() {
   await promiseTabRestored(tab);
   browser = tab.linkedBrowser;
 
-  await ContentTask.spawn(browser, null, function() {
-    is(content.document.getElementById("test_id2").value, "ok",
-       "CSP should block the script loaded by the clicked data URI after restore");
+  await ContentTask.spawn(browser, {dataURIPref}, function({dataURIPref}) { // eslint-disable-line
+    if (dataURIPref) {
+      is(content.document.getElementById("test_id2").value, "id2_modified",
+         "data: URI should *not* inherit the CSP of the enclosing context");
+    } else {
+      is(content.document.getElementById("test_id2").value, "id2_initial",
+        "CSP should block the script loaded by the clicked data URI after restore");
+    }
   });
 
   // clean up
diff --git browser/components/sessionstore/test/browser_911547_sample.html browser/components/sessionstore/test/browser_911547_sample.html
index ccc2011593d4..73cb99ee41f1 100644
--- browser/components/sessionstore/test/browser_911547_sample.html
+++ browser/components/sessionstore/test/browser_911547_sample.html
@@ -8,12 +8,12 @@
 
   <!--
    this element gets modified by an injected script;
-   that script should be blocked by CSP.
+   that script should be blocked by CSP if security.data_uri.unique_opaque_origin == false;
    Inline scripts can modify it, but not data uris.
   -->
-  <input type="text" id="test_id" value="ok">
+  <input type="text" id="test_id1" value="id1_initial">
 
-  <a id="test_data_link" href="data:text/html;charset=utf-8,<input type='text' id='test_id2' value='ok'/> <script>document.getElementById('test_id2').value = 'fail';</script>">Test Link</a>
+  <a id="test_data_link" href="data:text/html;charset=utf-8,<input type='text' id='test_id2' value='id2_initial'/> <script>document.getElementById('test_id2').value = 'id2_modified';</script>">Test Link</a>
 
 </body>
 </html>

commit 8b999864f0bb
Author: Christoph Kerschbaumer <ckerschb@christophkerschbaumer.com>
Date:   Fri Aug 4 14:10:38 2017 +0200

    Bug 1381761 - Test data: URIs inherit the CSP even if treated as unique, opaque origins. r=dveditz
---
 .../test/csp/file_data_csp_inheritance.html        | 21 +++++++++++++
 dom/security/test/csp/mochitest.ini                |  2 ++
 .../test/csp/test_data_csp_inheritance.html        | 34 ++++++++++++++++++++++
 3 files changed, 57 insertions(+)

diff --git dom/security/test/csp/file_data_csp_inheritance.html dom/security/test/csp/file_data_csp_inheritance.html
new file mode 100644
index 000000000000..299c30255aa6
--- /dev/null
+++ dom/security/test/csp/file_data_csp_inheritance.html
@@ -0,0 +1,21 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Bug 1381761 - Treating 'data:' documents as unique, opaque origins should still inherit the CSP</title>
+  <meta charset="utf-8">
+  <meta http-equiv="Content-Security-Policy" content= "img-src 'none'"/>
+</head>
+<body>
+<iframe id="dataFrame" src="data:text/html,<body>should inherit csp</body>"></iframe>
+
+<script type="application/javascript">
+  // get the csp in JSON notation from the principal
+  var frame = document.getElementById("dataFrame");
+  var principal = SpecialPowers.wrap(frame.contentDocument).nodePrincipal;
+  var cspJSON = principal.cspJSON;
+  var result = principal.cspJSON ? "dataInheritsCSP" : "dataDoesNotInheritCSP";
+  window.parent.postMessage({result}, "*");
+</script>
+
+</body>
+</html>
diff --git dom/security/test/csp/mochitest.ini dom/security/test/csp/mochitest.ini
index ba391ad59799..09f80b2969d7 100644
--- dom/security/test/csp/mochitest.ini
+++ dom/security/test/csp/mochitest.ini
@@ -217,6 +217,7 @@ support-files =
   file_ignore_xfo.html^headers^
   file_ro_ignore_xfo.html
   file_ro_ignore_xfo.html^headers^
+  file_data_csp_inheritance.html
   file_report_font_cache-1.html
   file_report_font_cache-2.html
   file_report_font_cache-2.html^headers^
@@ -308,4 +309,5 @@ tags = mcb
 [test_websocket_self.html]
 skip-if = toolkit == 'android'
 [test_ignore_xfo.html]
+[test_data_csp_inheritance.html]
 [test_data_csp_merge.html]
diff --git dom/security/test/csp/test_data_csp_inheritance.html dom/security/test/csp/test_data_csp_inheritance.html
new file mode 100644
index 000000000000..3afc4f7c02bc
--- /dev/null
+++ dom/security/test/csp/test_data_csp_inheritance.html
@@ -0,0 +1,34 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Bug 1381761 - Treating 'data:' documents as unique, opaque origins should still inherit the CSP</title>
+  <!-- Including SimpleTest.js so we can use waitForExplicitFinish !-->
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<iframe style="width:100%;" id="testframe"></iframe>
+
+<script class="testbody" type="text/javascript">
+
+SimpleTest.waitForExplicitFinish();
+
+/* Description of the test:
+ * We load an iframe using a meta CSP which includes another iframe
+ * using a data: URI. We make sure the CSP gets inherited into
+ * the data: URI iframe.
+ */
+
+window.addEventListener("message", receiveMessage);
+function receiveMessage(event) {
+  window.removeEventListener("message", receiveMessage);
+  is(event.data.result, "dataInheritsCSP",
+     "data: URI iframe inherits CSP from including context");
+  SimpleTest.finish();
+}
+
+document.getElementById("testframe").src = "file_data_csp_inheritance.html";
+
+</script>
+</body>
+</html>