| Index: Source/WebCore/dom/Document.cpp
|
| ===================================================================
|
| --- Source/WebCore/dom/Document.cpp (revision 112895)
|
| +++ Source/WebCore/dom/Document.cpp (working copy)
|
| @@ -339,6 +339,34 @@
|
| #endif
|
| }
|
|
|
| +static bool canAccessAncestor(const SecurityOrigin* activeSecurityOrigin, 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 (Frame* ancestorFrame = targetFrame; ancestorFrame; ancestorFrame = ancestorFrame->tree()->parent()) {
|
| + Document* ancestorDocument = ancestorFrame->document();
|
| + // FIXME: Should be an ASSERT? Frames should alway have documents.
|
| + if (!ancestorDocument)
|
| + return true;
|
| +
|
| + const SecurityOrigin* ancestorSecurityOrigin = ancestorDocument->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;
|
| +}
|
| +
|
| static HashSet<Document*>* documentsThatNeedStyleRecalc = 0;
|
|
|
| class DocumentWeakReference : public ThreadSafeRefCounted<DocumentWeakReference> {
|
| @@ -2534,6 +2562,61 @@
|
| frame()->script()->disableEval();
|
| }
|
|
|
| +bool Document::canNavigate(Frame* targetFrame)
|
| +{
|
| + // The navigation change is safe if the active document is:
|
| + // - in the same security origin as the target or one of the target's
|
| + // ancestors.
|
| + //
|
| + // Or the target frame is:
|
| + // - a top-level frame in the frame hierarchy and the active frame can
|
| + // navigate the target frame's opener per above or it is the opener of
|
| + // the target frame.
|
| +
|
| + if (!m_frame)
|
| + return false;
|
| +
|
| + // FIXME: Do we actually ever call this function without a targetFrame?
|
| + if (!targetFrame)
|
| + return true;
|
| +
|
| + // Performance optimization.
|
| + // FIXME: Delete this code. It seems very unlikely that this affects performance.
|
| + if (m_frame == targetFrame)
|
| + return true;
|
| +
|
| + // Let a document navigate window.top so that it can framebust.
|
| + if (!isSandboxed(SandboxTopNavigation) && targetFrame == m_frame->tree()->top())
|
| + return true;
|
| +
|
| + // A sandboxed frame can only navigate itself and its descendants.
|
| + if (isSandboxed(SandboxNavigation) && !targetFrame->tree()->isDescendantOf(m_frame))
|
| + return false;
|
| +
|
| + // Let a frame navigate its opener if the opener is a top-level window.
|
| + if (!targetFrame->tree()->parent() && m_frame->loader()->opener() == targetFrame)
|
| + return true;
|
| +
|
| + // For top-level windows, check the opener.
|
| + // FIXME: Can this check be combined with the previous check?
|
| + if (!targetFrame->tree()->parent() && canAccessAncestor(securityOrigin(), targetFrame->loader()->opener()))
|
| + return true;
|
| +
|
| + // In general, check the frame's ancestors.
|
| + if (canAccessAncestor(securityOrigin(), targetFrame))
|
| + return true;
|
| +
|
| + Document* targetDocument = targetFrame->document();
|
| + // FIXME: this error message should contain more specifics of why the navigation change is not allowed.
|
| + String message = "Unsafe JavaScript attempt to initiate a navigation change for frame with URL " +
|
| + targetDocument->url().string() + " from frame with URL " + url().string() + ".\n";
|
| +
|
| + // FIXME: should we print to the console of the activeFrame as well?
|
| + targetFrame->domWindow()->printErrorMessage(message);
|
| +
|
| + return false;
|
| +}
|
| +
|
| CSSStyleSheet* Document::pageUserSheet()
|
| {
|
| if (m_pageUserSheet)
|
|
|