Skip to content

Commit

Permalink
Tighten up the named-target navigation policy to better match the HTM…
Browse files Browse the repository at this point in the history
…L5 spec and Safari. Bug 408052, patch by Adam Barth <hk9565@gmail.com> and Collin Jackson <mozilla@collinjackson.com>, r=jst, sr=bzbarsky.
  • Loading branch information
bzbarsky committed Jan 27, 2008
1 parent 53278fe commit 147ee0e
Show file tree
Hide file tree
Showing 21 changed files with 1,060 additions and 66 deletions.
89 changes: 23 additions & 66 deletions docshell/base/nsDocShell.cpp
Expand Up @@ -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?

// For historical context, see:
//
// Bug 13871: Prevent frameset spoofing
// Bug 103638: Targets with same name in different windows open in wrong
// window with javascript

// 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.
//
// 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).

nsCOMPtr<nsIDocShellTreeItem> targetRoot;
aTargetItem->GetSameTypeRootTreeItem(getter_AddRefs(targetRoot));
if (aTargetItem == aAccessingItem) {
// A frame is allowed to navigate itself.
return PR_TRUE;
}

nsCOMPtr<nsIDocShellTreeItem> 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<nsIDocShellTreeItem> target = aTargetItem;
do {
if (ValidateOrigin(aAccessingItem, target)) {
Expand All @@ -1947,6 +1945,9 @@ nsDocShell::CanAccessItem(nsIDocShellTreeItem* aTargetItem,
parent.swap(target);
} while (target);

nsCOMPtr<nsIDocShellTreeItem> 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
Expand Down Expand Up @@ -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<nsIJSContextStack> 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<nsIDocShellTreeItem> callerTreeItem;
nsCOMPtr<nsPIDOMWindow> win;
if (currentCX &&
(win = do_QueryInterface(currentCX->GetGlobalObject())) &&
(callerTreeItem = do_QueryInterface(win->GetDocShell()))) {
nsCOMPtr<nsIDocShellTreeItem> callerRoot;
callerTreeItem->GetSameTypeRootTreeItem(getter_AddRefs(callerRoot));

nsCOMPtr<nsIDocShellTreeItem> 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;
}

Expand Down
1 change: 1 addition & 0 deletions docshell/test/Makefile.in
Expand Up @@ -45,6 +45,7 @@ MODULE = test_docshell

DIRS += chrome \
browser \
navigation \
$(NULL)

XPCSHELL_TESTS = unit
Expand Down
73 changes: 73 additions & 0 deletions 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)

0 comments on commit 147ee0e

Please sign in to comment.