Bug 723808: don't allow loads in type=content docshells to inherit the system principal, r=bz, a=lsblakk
authorGavin Sharp <gavin@gavinsharp.com>
Mon, 30 Jan 2012 18:29:44 -0800
changeset 81692 c2b28e09323c
parent 81691 7b68d8316c3d
child 81693 64e2d498a321
push id35
push usergsharp@mozilla.com
push date2012-02-28 19:56 +0000
reviewersbz, lsblakk
bugs723808
milestone10.0.2
Bug 723808: don't allow loads in type=content docshells to inherit the system principal, r=bz, a=lsblakk
docshell/base/nsDocShell.cpp
docshell/test/chrome/Makefile.in
docshell/test/chrome/test_principalInherit.xul
dom/tests/mochitest/chrome/window_focus.xul
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -8627,19 +8627,21 @@ nsDocShell::InternalLoad(nsIURI * aURI,
 
     return rv;
 }
 
 nsIPrincipal*
 nsDocShell::GetInheritedPrincipal(bool aConsiderCurrentDocument)
 {
     nsCOMPtr<nsIDocument> document;
+    bool inheritedFromCurrent = false;
 
     if (aConsiderCurrentDocument && mContentViewer) {
         document = mContentViewer->GetDocument();
+        inheritedFromCurrent = true;
     }
 
     if (!document) {
         nsCOMPtr<nsIDocShellTreeItem> parentItem;
         GetSameTypeParent(getter_AddRefs(parentItem));
         if (parentItem) {
             document = do_GetInterface(parentItem);
         }
@@ -8657,17 +8659,27 @@ nsDocShell::GetInheritedPrincipal(bool a
 
         if (!mContentViewer)
             return nsnull;
         document = mContentViewer->GetDocument();
     }
 
     //-- Get the document's principal
     if (document) {
-        return document->NodePrincipal();
+        nsIPrincipal *docPrincipal = document->NodePrincipal();
+
+        // Don't allow loads in typeContent docShells to inherit the system
+        // principal from existing documents.
+        if (inheritedFromCurrent &&
+            mItemType == typeContent &&
+            nsContentUtils::IsSystemPrincipal(docPrincipal)) {
+            return nsnull;
+        }
+
+        return docPrincipal;
     }
 
     return nsnull;
 }
 
 bool
 nsDocShell::ShouldCheckAppCache(nsIURI *aURI)
 {
--- a/docshell/test/chrome/Makefile.in
+++ b/docshell/test/chrome/Makefile.in
@@ -117,16 +117,17 @@ include $(topsrcdir)/config/rules.mk
 		test_bug456980.xul \
 		test_bug662200.xul \
 		bug662200_window.xul \
 		662200a.html \
 		662200b.html \
 		662200c.html \
 		test_bug690056.xul \
 		bug690056_window.xul \
+		test_principalInherit.xul \
 		$(NULL)
 
 _DOCSHELL_SUBHARNESS = \
     docshell_helpers.js \
     generic.html \
     $(NULL)
 
 libs:: $(_HTTP_FILES)
new file mode 100644
--- /dev/null
+++ b/docshell/test/chrome/test_principalInherit.xul
@@ -0,0 +1,110 @@
+<?xml version="1.0"?>
+<!-- Any copyright is dedicated to the Public Domain.
+   - http://creativecommons.org/publicdomain/zero/1.0/ -->
+<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
+<?xml-stylesheet
+  href="chrome://mochikit/content/tests/SimpleTest/test.css"
+  type="text/css"?>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=719994
+-->
+<window title="Test principal inheriting"
+  xmlns:html="http://www.w3.org/1999/xhtml"
+  xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+  <title>Test principal inheriting</title>
+  <script type="application/javascript"
+          src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+
+<body xmlns="http://www.w3.org/1999/xhtml">
+<p id="display"></p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+</pre>
+</body>
+
+<script class="testbody" type="application/javascript">
+<![CDATA[
+
+/** Test for Bug 719994 **/
+
+SimpleTest.waitForExplicitFinish();
+
+var gFrame;
+
+// This test file is loaded in a type=content docshell whose principal is
+// the system principal.
+
+// Using data: URIs here instead of javascript: URIs, since javascript: URIs
+// fail to load when there's no principal to load them against. This only
+// matters when these tests fail (produces better error messages).
+var tests = [
+  function testInheritFromParent(cb) {
+    gFrame = document.createElement("iframe");
+    loadListener(gFrame, function () {
+      is(window.inheritedFromParent, true, "load in type=content iframe inherited principal of same type parent");
+      cb();
+    });
+    gFrame.setAttribute("type", "content");
+    gFrame.setAttribute("src", "data:text/html,<script>parent.inheritedFromParent = true;</script>");
+    document.documentElement.appendChild(gFrame);
+  },
+  function testInheritFromCurrent_system(cb) {
+    loadListener(gFrame, function () {
+      is(window.inheritedSystem, undefined, "load in type=content iframe shouldn't inherit system principal from current document");
+      cb();
+    }, true);
+    gFrame.setAttribute("src", "data:text/html,<script>parent.inheritedSystem = true;</script>");
+  },
+  function testInheritFromCreated(cb) {
+    // Open a new chrome window with a type="content" iframe, so that it has no
+    // same-type parent.
+    // Load a javascript: URI in it to ensure that GetInheritedPrincipal will
+    // force creation of a content viewer.
+    let xulWinURL = 'data:application/vnd.mozilla.xul+xml,<?xml version="1.0"?>' +
+                    '<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"/>';
+    let newWin = window.openDialog(xulWinURL, "chrome_window", "chrome");
+    loadListener(newWin, function () {
+      let frame = newWin.document.createElement("iframe");
+      frame.setAttribute("type", "content");
+      frame.setAttribute("src", "javascript:'1';");
+      loadListener(frame, function () {
+        is(frame.contentWindow.document.body.textContent, "1", "content viewer was created");
+        SimpleTest.executeSoon(function () {
+          newWin.close();
+          cb();
+        })
+      });
+      newWin.document.documentElement.appendChild(frame);
+    });
+  }
+];
+
+addLoadEvent(function onLoad() {
+  ok(Components.stack, "this test must be run with the system principal");
+  SimpleTest.executeSoon(nextTest);
+});
+
+function loadListener(target, func) {
+  target.addEventListener("load", function lis() {
+    target.removeEventListener("load", lis, true);
+    func();
+  }, true);
+}
+
+function nextTest() {
+  if (tests.length) {
+    let test = tests.shift();
+    SimpleTest.executeSoon(function () {
+      SimpleTest.info("running " + test.name);
+      test(nextTest);
+    });
+  } else
+    SimpleTest.executeSoon(SimpleTest.finish);
+}
+
+]]>
+</script>
+
+</window>
--- a/dom/tests/mochitest/chrome/window_focus.xul
+++ b/dom/tests/mochitest/chrome/window_focus.xul
@@ -1538,30 +1538,25 @@ function doFrameSwitchingTests()
   doFrameHistoryTests()
 }
 
 function doFrameHistoryTests()
 {
   var t20 = getById("t20");
   t20.focus();
 
-  addEventListener("message", function() { $("childframe").goBack(); }, true);
   gChildWindow.addEventListener("focus",
     function(event) {
       if (event.target == t20) {
         is(fm.focusedElement, t20, "focus restored after history back"); done();
     }
   }, true);
 
   // make sure that loading a new page and then going back maintains the focus
-  gChildWindow.location = "data:text/html,<html><body onload='window.QueryInterface(Components.interfaces.nsIInterfaceRequestor)." +
-                          "getInterface(Components.interfaces.nsIWebNavigation)." +
-                          "QueryInterface(Components.interfaces.nsIDocShellTreeItem).rootTreeItem." +
-                          "QueryInterface(Components.interfaces.nsIInterfaceRequestor)." +
-                          "getInterface(Components.interfaces.nsIDOMWindow).postMessage(\"content loaded\", \"*\");'>Next</body></html>";
+  gChildWindow.location = "data:text/html,<script>window.onload=function() {setTimeout(function () {window.back();}, 0);}</script>";
 }
 
 function addFrameSwitchingListeners(frame)
 {
   frame.contentWindow.addEventListener("focus", frameSwitchingEventOccured, false);
   frame.contentWindow.addEventListener("blur", frameSwitchingEventOccured, false);
   frame.contentDocument.addEventListener("focus", frameSwitchingEventOccured, false);
   frame.contentDocument.addEventListener("blur", frameSwitchingEventOccured, false);