| Index: Source/core/frame/Frame.cpp
|
| diff --git a/Source/core/frame/Frame.cpp b/Source/core/frame/Frame.cpp
|
| index b121c1ac38e139e876ab97d5fde16cd72e4f50db..c84121d3b075c7109510c707480acadf2d4fef66 100644
|
| --- a/Source/core/frame/Frame.cpp
|
| +++ b/Source/core/frame/Frame.cpp
|
| @@ -150,6 +150,104 @@ ChromeClient& Frame::chromeClient() const
|
| return emptyChromeClient();
|
| }
|
|
|
| +Frame* Frame::findFrameForNavigation(const AtomicString& name, Frame& activeFrame)
|
| +{
|
| + Frame* frame = tree().find(name);
|
| + if (!frame || !activeFrame.canNavigate(*frame))
|
| + return nullptr;
|
| + return frame;
|
| +}
|
| +
|
| +static bool canAccessAncestor(const SecurityOrigin& activeSecurityOrigin, const Frame* targetFrame)
|
| +{
|
| + // targetFrame can be 0 when we're trying to navigate a top-level frame
|
| + // that has a 0 opener.
|
| + if (!targetFrame)
|
| + return false;
|
| +
|
| + const bool isLocalActiveOrigin = activeSecurityOrigin.isLocal();
|
| + for (const Frame* ancestorFrame = targetFrame; ancestorFrame; ancestorFrame = ancestorFrame->tree().parent()) {
|
| + const SecurityOrigin* ancestorSecurityOrigin = ancestorFrame->securityContext()->securityOrigin();
|
| + if (activeSecurityOrigin.canAccess(ancestorSecurityOrigin))
|
| + return true;
|
| +
|
| + // Allow file URL descendant navigation even when allowFileAccessFromFileURLs is false.
|
| + // FIXME: It's a bit strange to special-case local origins here. Should we be doing
|
| + // something more general instead?
|
| + if (isLocalActiveOrigin && ancestorSecurityOrigin->isLocal())
|
| + return true;
|
| + }
|
| +
|
| + return false;
|
| +}
|
| +
|
| +bool Frame::canNavigate(const Frame& targetFrame)
|
| +{
|
| + // Frame-busting is generally allowed, but blocked for sandboxed frames lacking the 'allow-top-navigation' flag.
|
| + if (!securityContext()->isSandboxed(SandboxTopNavigation) && targetFrame == tree().top())
|
| + return true;
|
| +
|
| + if (securityContext()->isSandboxed(SandboxNavigation)) {
|
| + if (targetFrame.tree().isDescendantOf(this))
|
| + return true;
|
| +
|
| + const char* reason = "The frame attempting navigation is sandboxed, and is therefore disallowed from navigating its ancestors.";
|
| + if (securityContext()->isSandboxed(SandboxTopNavigation) && targetFrame == tree().top())
|
| + reason = "The frame attempting navigation of the top-level window is sandboxed, but the 'allow-top-navigation' flag is not set.";
|
| +
|
| + printNavigationErrorMessage(targetFrame, reason);
|
| + return false;
|
| + }
|
| +
|
| + ASSERT(securityContext()->securityOrigin());
|
| + SecurityOrigin& origin = *securityContext()->securityOrigin();
|
| +
|
| + // This is the normal case. A document can navigate its decendant frames,
|
| + // or, more generally, a document can navigate a frame if the document is
|
| + // in the same origin as any of that frame's ancestors (in the frame
|
| + // hierarchy).
|
| + //
|
| + // See http://www.adambarth.com/papers/2008/barth-jackson-mitchell.pdf for
|
| + // historical information about this security check.
|
| + if (canAccessAncestor(origin, &targetFrame))
|
| + return true;
|
| +
|
| + // Top-level frames are easier to navigate than other frames because they
|
| + // display their URLs in the address bar (in most browsers). However, there
|
| + // are still some restrictions on navigation to avoid nuisance attacks.
|
| + // Specifically, a document can navigate a top-level frame if that frame
|
| + // opened the document or if the document is the same-origin with any of
|
| + // the top-level frame's opener's ancestors (in the frame hierarchy).
|
| + //
|
| + // In both of these cases, the document performing the navigation is in
|
| + // some way related to the frame being navigate (e.g., by the "opener"
|
| + // and/or "parent" relation). Requiring some sort of relation prevents a
|
| + // document from navigating arbitrary, unrelated top-level frames.
|
| + if (!targetFrame.tree().parent()) {
|
| + if (targetFrame == client()->opener())
|
| + return true;
|
| + if (canAccessAncestor(origin, targetFrame.client()->opener()))
|
| + return true;
|
| + }
|
| +
|
| + printNavigationErrorMessage(targetFrame, "The frame attempting navigation is neither same-origin with the target, nor is it the target's parent or opener.");
|
| + return false;
|
| +}
|
| +
|
| +Frame* Frame::findUnsafeParentScrollPropagationBoundary()
|
| +{
|
| + Frame* currentFrame = this;
|
| + Frame* ancestorFrame = tree().parent();
|
| +
|
| + while (ancestorFrame) {
|
| + if (!ancestorFrame->securityContext()->securityOrigin()->canAccess(securityContext()->securityOrigin()))
|
| + return currentFrame;
|
| + currentFrame = ancestorFrame;
|
| + ancestorFrame = ancestorFrame->tree().parent();
|
| + }
|
| + return nullptr;
|
| +}
|
| +
|
| RenderPart* Frame::ownerRenderer() const
|
| {
|
| if (!deprecatedLocalOwner())
|
|
|