Bug 723808: disallow inheriting of system principal in type=content docshells, r=bz, a=lsblakk
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -8082,23 +8082,25 @@ nsDocShell::InternalLoad(nsIURI * aURI,
return rv;
}
nsIPrincipal*
nsDocShell::GetInheritedPrincipal(PRBool aConsiderCurrentDocument)
{
nsCOMPtr<nsIDocument> document;
+ PRBool inheritedFromCurrent = PR_FALSE;
if (aConsiderCurrentDocument && mContentViewer) {
nsCOMPtr<nsIDocumentViewer>
docViewer(do_QueryInterface(mContentViewer));
if (!docViewer)
return nsnull;
docViewer->GetDocument(getter_AddRefs(document));
+ inheritedFromCurrent = PR_TRUE;
}
if (!document) {
nsCOMPtr<nsIDocShellTreeItem> parentItem;
GetSameTypeParent(getter_AddRefs(parentItem));
if (parentItem) {
nsCOMPtr<nsIDOMDocument> parentDomDoc(do_GetInterface(parentItem));
document = do_QueryInterface(parentDomDoc);
@@ -8119,17 +8121,27 @@ nsDocShell::GetInheritedPrincipal(PRBool
docViewer(do_QueryInterface(mContentViewer));
if (!docViewer)
return nsnull;
docViewer->GetDocument(getter_AddRefs(document));
}
//-- 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;
}
PRBool
nsDocShell::ShouldCheckAppCache(nsIURI *aURI)
{
--- a/docshell/test/chrome/Makefile.in
+++ b/docshell/test/chrome/Makefile.in
@@ -97,16 +97,17 @@ include $(topsrcdir)/config/rules.mk
test_bug428288.html \
test_bug449778.xul \
bug449778_window.xul \
test_bug449780.xul \
bug449780_window.xul \
test_bug454235.xul \
bug454235-subframe.xul \
test_bug456980.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,92 @@
+<?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/MochiKit/packed.js"></script>
+ <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 () {
+ netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
+ 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 () {
+ netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
+ 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>");
+ }
+];
+
+addLoadEvent(function onLoad() {
+ 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 () {
+ netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
+ ok(Components.stack, "this test must be run with the system principal");
+ 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
@@ -1432,30 +1432,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);