diff --git a/mozilla/docshell/base/nsDocShell.cpp b/mozilla/docshell/base/nsDocShell.cpp index 57c77ff542c..d3d33f382f9 100644 --- a/mozilla/docshell/base/nsDocShell.cpp +++ b/mozilla/docshell/base/nsDocShell.cpp @@ -1905,37 +1905,35 @@ nsDocShell::CanAccessItem(nsIDocShellTreeItem* aTargetItem, // XXXbz should we care if aAccessingItem or the document therein is // chrome? Should those get extra privileges? - // Now do a security check - // Bug 13871: Prevent frameset spoofing - // See BugSplat 336170, 338737 and XP_FindNamedContextInList in - // the classic codebase - // Nav's behaviour was: - // - pref controlled: "browser.frame.validate_origin" - // (gValidateOrigin) - // - allow load if host of target or target's parent is same - // as host of origin - // - allow load if target is a top level window - - // We are going to be a little more restrictive, with the - // following algorithm: - // - pref controlled in the same way - // - allow access if the two treeitems are in the same tree - // - allow access if the aTargetItem or one of its ancestors - // has the same origin as aAccessingItem - // - allow access if the target is a toplevel window and we can - // access its opener. Note that we only allow one level of - // recursion there. + // For historical context, see: + // + // Bug 13871: Prevent frameset spoofing + // Bug 103638: Targets with same name in different windows open in wrong + // window with javascript - nsCOMPtr targetRoot; - aTargetItem->GetSameTypeRootTreeItem(getter_AddRefs(targetRoot)); + // Now do a security check + // + // Allow navigation if + // 1) aAccessingItem can script aTargetItem or one of its ancestors in + // the frame hierarchy or + // 2) aTargetItem is a top-level frame and aAccessingItem is its descendant + // 3) aTargetItem is a top-level frame and aAccessingItem can target + // its opener per rule (1) or (2). + + if (aTargetItem == aAccessingItem) { + // A frame is allowed to navigate itself. + return PR_TRUE; + } nsCOMPtr accessingRoot; aAccessingItem->GetSameTypeRootTreeItem(getter_AddRefs(accessingRoot)); - if (targetRoot == accessingRoot) { + if (aTargetItem == accessingRoot) { + // A frame can navigate its root. return PR_TRUE; } + // Check if aAccessingItem can navigate one of aTargetItem's ancestors. nsCOMPtr target = aTargetItem; do { if (ValidateOrigin(aAccessingItem, target)) { @@ -1947,6 +1945,9 @@ nsDocShell::CanAccessItem(nsIDocShellTreeItem* aTargetItem, parent.swap(target); } while (target); + nsCOMPtr targetRoot; + aTargetItem->GetSameTypeRootTreeItem(getter_AddRefs(targetRoot)); + if (aTargetItem != targetRoot) { // target is a subframe, not in accessor's frame hierarchy, and all its // ancestors have origins different from that of the accessor. Don't @@ -6419,50 +6420,6 @@ nsDocShell::CheckLoadingPermissions() item.swap(tmp); } while (item); - // The caller is not from the same origin as this item, or any if - // this items ancestors. Only permit loading content if both are - // part of the same window, assuming we can find the window of the - // caller. - - nsCOMPtr stack = - do_GetService("@mozilla.org/js/xpc/ContextStack;1"); - if (!stack) { - // No context stack available. Should never happen, but in - // case it does, return the sameOrigin error from the security - // check above. - - return sameOrigin; - } - - JSContext *cx = nsnull; - stack->Peek(&cx); - - if (!cx) { - // No caller docshell reachable, return the sameOrigin error - // from the security check above. - - return sameOrigin; - } - - nsIScriptContext *currentCX = GetScriptContextFromJSContext(cx); - nsCOMPtr callerTreeItem; - nsCOMPtr win; - if (currentCX && - (win = do_QueryInterface(currentCX->GetGlobalObject())) && - (callerTreeItem = do_QueryInterface(win->GetDocShell()))) { - nsCOMPtr callerRoot; - callerTreeItem->GetSameTypeRootTreeItem(getter_AddRefs(callerRoot)); - - nsCOMPtr ourRoot; - GetSameTypeRootTreeItem(getter_AddRefs(ourRoot)); - - if (ourRoot == callerRoot) { - // The running JS is in the same window as the target - // frame, permit load. - sameOrigin = NS_OK; - } - } - return sameOrigin; } diff --git a/mozilla/docshell/test/Makefile.in b/mozilla/docshell/test/Makefile.in index 745bc73a90f..c4fbb9b6f8b 100644 --- a/mozilla/docshell/test/Makefile.in +++ b/mozilla/docshell/test/Makefile.in @@ -45,6 +45,7 @@ MODULE = test_docshell DIRS += chrome \ browser \ + navigation \ $(NULL) XPCSHELL_TESTS = unit diff --git a/mozilla/docshell/test/navigation/Makefile.in b/mozilla/docshell/test/navigation/Makefile.in new file mode 100644 index 00000000000..35081a5dd6e --- /dev/null +++ b/mozilla/docshell/test/navigation/Makefile.in @@ -0,0 +1,73 @@ +# +# ***** BEGIN LICENSE BLOCK ***** # Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# # The Original Code is mozilla.org code. +# +# The Initial Developer of the Original Code is +# Mozilla Foundation. +# Portions created by the Initial Developer are Copyright (C) 2007 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either of the GNU General Public License Version 2 or later (the "GPL"), +# or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +DEPTH = ../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ +relativesrcdir = docshell/test/navigation + +MODULE = test_docshell + +DIRS += $(NULL) + +XPCSHELL_TESTS = unit + +include $(DEPTH)/config/autoconf.mk +include $(topsrcdir)/config/rules.mk + +_TEST_FILES = \ + test_bug13871.html \ + test_bug270414.html \ + test_bug278916.html \ + test_bug279495.html \ + test_child.html \ + test_grandchild.html \ + test_sibling-off-domain.html \ + test_sibling-matching-parent.html \ + test_opener.html \ + test_not-opener.html \ + test_popup-navigates-children.html \ + test_reserved.html \ + NavigationUtils.js \ + navigate.html \ + open.html \ + iframe.html \ + parent.html \ + blank.html \ + $(NULL) + +libs:: $(_TEST_FILES) + $(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/tests/$(relativesrcdir) diff --git a/mozilla/docshell/test/navigation/NavigationUtils.js b/mozilla/docshell/test/navigation/NavigationUtils.js new file mode 100644 index 00000000000..bb23547d6f4 --- /dev/null +++ b/mozilla/docshell/test/navigation/NavigationUtils.js @@ -0,0 +1,231 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is NavigationUtils.js + * + * The Initial Developer of the Original Code is + * Stanford University + * Portions created by the Initial Developer are Copyright (C) 2008 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Adam Barth + * Collin Jackson + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/////////////////////////////////////////////////////////////////////////// +// +// Utilities for navigation tests +// +/////////////////////////////////////////////////////////////////////////// + +var body = "This frame was navigated."; +var target_url = "data:text/html," + body + ""; + +/////////////////////////////////////////////////////////////////////////// +// Functions that navigate frames +/////////////////////////////////////////////////////////////////////////// + +function navigateByLocation(wnd) { + try { + wnd.location = target_url; + } catch(ex) { + // We need to keep our finished frames count consistent. + // Oddly, this ends up simulating the behavior of IE7. + window.open(target_url, "_blank", "width=10,height=10"); + } +} + +function navigateByOpen(name) { + window.open(target_url, name, "width=10,height=10"); +} + +function navigateByForm(name) { + var form = document.createElement("form"); + form.action = target_url; + form.method = "POST"; + form.target = name; document.body.appendChild(form); + form.submit(); +} + +var hyperlink_count = 0; + +function navigateByHyperlink(name) { + var link = document.createElement("a"); + link.href = target_url; + link.target = name; + link.id = "navigation_hyperlink_" + hyperlink_count++; + document.body.appendChild(link); + sendMouseEvent({type:"click"}, link.id); +} + +/////////////////////////////////////////////////////////////////////////// +// Functions that call into Mochitest framework +/////////////////////////////////////////////////////////////////////////// + +function isNavigated(wnd, message) { + var result = null; + try { + result = wnd.document.body.innerHTML; + } catch(ex) { + result = ex; + } + is(result, body, message); +} + +function isBlank(wnd, message) { + var result = null; + try { + result = wnd.document.body.innerHTML; + } catch(ex) { + result = ex; + } + is(result, "This is a blank document.", message); +} + +function isAccessible(wnd, message) { + try { + wnd.document.body.innerHTML; + ok(true, message); + } catch(ex) { + ok(false, message); + } +} + +function isInaccessible(wnd, message) { + try { + wnd.document.body.innerHTML; + ok(false, message); + } catch(ex) { + ok(true, message); + } +} + +/////////////////////////////////////////////////////////////////////////// +// Functions that require UniversalXPConnect privilege +/////////////////////////////////////////////////////////////////////////// + +// Note: This only searches for top-level frames with this name. +function xpcGetFramesByName(name) { + netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); + var ww = Components.classes["@mozilla.org/embedcomp/window-watcher;1"] + .getService(Components.interfaces.nsIWindowWatcher); + var enumerator = ww.getWindowEnumerator(); + + var results = []; + + while (enumerator.hasMoreElements()) { + var win = enumerator.getNext(); + var tabs = win.gBrowser.browsers; + + for (var i = 0; i < tabs.length; i++) { + var domwindow = tabs[i].docShell.document.defaultView; + + if (domwindow.name == name) + results.push(domwindow); + } + } + + return results; +} + +function xpcCleanupWindows() { + netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); + var ww = Components.classes["@mozilla.org/embedcomp/window-watcher;1"] + .getService(Components.interfaces.nsIWindowWatcher); + var enumerator = ww.getWindowEnumerator(); + + while (enumerator.hasMoreElements()) { + var win = enumerator.getNext(); + var tabs = win.gBrowser.browsers; + + for (var i = 0; i < tabs.length; i++) { + var domwindow = tabs[i].docShell.document.defaultView; + + if (domwindow.location.protocol == "data:") + domwindow.close(); + } + } +} + +function xpcWaitForFinishedFrames(callback, numFrames) { + var finishedFrameCount = 0; + function frameFinished() { + finishedFrameCount++; + + if (finishedFrameCount == numFrames) { + clearInterval(frameWaitInterval); + setTimeout(callback, 1); + return; + } + + if (finishedFrameCount > numFrames) + throw "Too many frames loaded."; + } + + var finishedWindows = []; + + function contains(obj, arr) { + for (var i = 0; i < arr.length; i++) { + if (obj === arr[i]) + return true; + } + return false; + } + + function searchForFinishedFrames(win) { + if (escape(unescape(win.location)) == escape(target_url)) { + if (!contains(win, finishedWindows)) { + finishedWindows.push(win); + frameFinished(); + } + } + for (var i = 0; i < win.frames.length; i++) + searchForFinishedFrames(win.frames[i]); + } + + function poll() { + // This only gives us UniversalXPConnect for the current stack frame + // We're using setInterval, so the main page's privileges are still normal + netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); + var ww = Components.classes["@mozilla.org/embedcomp/window-watcher;1"] + .getService(Components.interfaces.nsIWindowWatcher); + var enumerator = ww.getWindowEnumerator(); + while (enumerator.hasMoreElements()) { + var win = enumerator.getNext(); + if (!win.gBrowser) + continue; // This window hasn't finished initializing + var tabs = win.gBrowser.browsers; + + for (var i = 0; i < tabs.length; i++) { + searchForFinishedFrames(tabs[i].docShell.document.defaultView); + } + } + } + + var frameWaitInterval = setInterval(poll, 500); +} + diff --git a/mozilla/docshell/test/navigation/blank.html b/mozilla/docshell/test/navigation/blank.html new file mode 100644 index 00000000000..245c62e8d1e --- /dev/null +++ b/mozilla/docshell/test/navigation/blank.html @@ -0,0 +1 @@ +This is a blank document. diff --git a/mozilla/docshell/test/navigation/iframe.html b/mozilla/docshell/test/navigation/iframe.html new file mode 100644 index 00000000000..4685fea7b7a --- /dev/null +++ b/mozilla/docshell/test/navigation/iframe.html @@ -0,0 +1,8 @@ + + + + + diff --git a/mozilla/docshell/test/navigation/navigate.html b/mozilla/docshell/test/navigation/navigate.html new file mode 100644 index 00000000000..dcb879b83a6 --- /dev/null +++ b/mozilla/docshell/test/navigation/navigate.html @@ -0,0 +1,30 @@ + + + + + + + + + diff --git a/mozilla/docshell/test/navigation/open.html b/mozilla/docshell/test/navigation/open.html new file mode 100644 index 00000000000..1bb70f865b2 --- /dev/null +++ b/mozilla/docshell/test/navigation/open.html @@ -0,0 +1,9 @@ + + + + + diff --git a/mozilla/docshell/test/navigation/parent.html b/mozilla/docshell/test/navigation/parent.html new file mode 100644 index 00000000000..46028aad935 --- /dev/null +++ b/mozilla/docshell/test/navigation/parent.html @@ -0,0 +1,11 @@ + + + +This document contains a frame. +
+ + + + diff --git a/mozilla/docshell/test/navigation/test_bug13871.html b/mozilla/docshell/test/navigation/test_bug13871.html new file mode 100644 index 00000000000..088a5b7ebc6 --- /dev/null +++ b/mozilla/docshell/test/navigation/test_bug13871.html @@ -0,0 +1,49 @@ + + + + + + + + + + + + +Mozilla Bug 13871 +
+
+
+ + diff --git a/mozilla/docshell/test/navigation/test_bug270414.html b/mozilla/docshell/test/navigation/test_bug270414.html new file mode 100644 index 00000000000..f0734daf16c --- /dev/null +++ b/mozilla/docshell/test/navigation/test_bug270414.html @@ -0,0 +1,94 @@ + + + + + + + + + + + + +Mozilla Bug 270414 +
+ + + + +
+
+
+
+ + diff --git a/mozilla/docshell/test/navigation/test_bug278916.html b/mozilla/docshell/test/navigation/test_bug278916.html new file mode 100644 index 00000000000..697ba11de86 --- /dev/null +++ b/mozilla/docshell/test/navigation/test_bug278916.html @@ -0,0 +1,40 @@ + + + + + + + + + + + +Mozilla Bug 278916 + +
+
+
+ + diff --git a/mozilla/docshell/test/navigation/test_bug279495.html b/mozilla/docshell/test/navigation/test_bug279495.html new file mode 100644 index 00000000000..86cc51eca5c --- /dev/null +++ b/mozilla/docshell/test/navigation/test_bug279495.html @@ -0,0 +1,49 @@ + + + + + + + + + + + +Mozilla Bug 279495 + +
+
+
+ + diff --git a/mozilla/docshell/test/navigation/test_child.html b/mozilla/docshell/test/navigation/test_child.html new file mode 100644 index 00000000000..f0a05f0e4a3 --- /dev/null +++ b/mozilla/docshell/test/navigation/test_child.html @@ -0,0 +1,45 @@ + + + + + + + + + + + + +Mozilla Bug 408052 +
+ + + + +
+
+
+
+ + diff --git a/mozilla/docshell/test/navigation/test_grandchild.html b/mozilla/docshell/test/navigation/test_grandchild.html new file mode 100644 index 00000000000..426fad06557 --- /dev/null +++ b/mozilla/docshell/test/navigation/test_grandchild.html @@ -0,0 +1,45 @@ + + + + + + + + + + + + +Mozilla Bug 408052 +
+ + + + +
+
+
+
+ + diff --git a/mozilla/docshell/test/navigation/test_not-opener.html b/mozilla/docshell/test/navigation/test_not-opener.html new file mode 100644 index 00000000000..072ee8ada14 --- /dev/null +++ b/mozilla/docshell/test/navigation/test_not-opener.html @@ -0,0 +1,48 @@ + + + + + + + + + + + + +Mozilla Bug 408052 +
+
+
+ + diff --git a/mozilla/docshell/test/navigation/test_opener.html b/mozilla/docshell/test/navigation/test_opener.html new file mode 100644 index 00000000000..c5a88a1bb20 --- /dev/null +++ b/mozilla/docshell/test/navigation/test_opener.html @@ -0,0 +1,49 @@ + + + + + + + + + + + + +Mozilla Bug 408052 +
+
+
+ + diff --git a/mozilla/docshell/test/navigation/test_popup-navigates-children.html b/mozilla/docshell/test/navigation/test_popup-navigates-children.html new file mode 100644 index 00000000000..8684c0400d0 --- /dev/null +++ b/mozilla/docshell/test/navigation/test_popup-navigates-children.html @@ -0,0 +1,63 @@ + + + + + + + + + + + + +
+ + + + +
+
+
+
+ + diff --git a/mozilla/docshell/test/navigation/test_reserved.html b/mozilla/docshell/test/navigation/test_reserved.html new file mode 100644 index 00000000000..7fb3af69d44 --- /dev/null +++ b/mozilla/docshell/test/navigation/test_reserved.html @@ -0,0 +1,97 @@ + + + + + + + + + + + + +Mozilla Bug 408052 +
+
+
+
+
+ + diff --git a/mozilla/docshell/test/navigation/test_sibling-matching-parent.html b/mozilla/docshell/test/navigation/test_sibling-matching-parent.html new file mode 100644 index 00000000000..fe84335b2da --- /dev/null +++ b/mozilla/docshell/test/navigation/test_sibling-matching-parent.html @@ -0,0 +1,47 @@ + + + + + + + + + + + + +Mozilla Bug 408052 +
+ + + + +
+
+
+
+
+ + diff --git a/mozilla/docshell/test/navigation/test_sibling-off-domain.html b/mozilla/docshell/test/navigation/test_sibling-off-domain.html new file mode 100644 index 00000000000..3d34188b1c0 --- /dev/null +++ b/mozilla/docshell/test/navigation/test_sibling-off-domain.html @@ -0,0 +1,47 @@ + + + + + + + + + + + + +Mozilla Bug 408052 +
+ + + + +
+
+
+
+
+ +