Changeset 231935 in webkit


Ignore:
Timestamp:
May 17, 2018 5:52:28 PM (6 years ago)
Author:
Chris Dumez
Message:

RenderLayer::scrollRectToVisible() should not propagate a subframe's scroll to its cross-origin parent
https://bugs.webkit.org/show_bug.cgi?id=185664
<rdar://problem/36185260>

Reviewed by Simon Fraser.

Source/WebCore:

RenderLayer::scrollRectToVisible() should not propagate a subframe's scroll to its
cross-origin parent. There was logic in FrameLoader::scrollToFragmentWithParentBoundary()
to temporarily set the 'safeToPropagateScrollToParent' flag to false on the cross-origin
ancestor frame during the call to FrameView::scrollToFragment(). This would correctly
prevent RenderLayer::scrollRectToVisible() to propagate the scroll to the cross-origin
ancestor frame when scrollRectToVisible() is called synchronously. However,
scrollRectToVisible() can get called asynchronously in case of a dirty layout, as part
of the post layout tasks.

To address the issue, we get rid of the safeToPropagateScrollToParent flag on FrameView
and instead update FrameView::safeToPropagateScrollToParent() to do the cross-origin
check. FrameView::safeToPropagateScrollToParent() is called by RenderLayer::scrollRectToVisible()
and this is a lot more robust than relying on a flag which gets temporarily set.

Test: http/tests/navigation/fragment-navigation-cross-origin-subframe-no-scrolling-parent.html

  • dom/Document.cpp:
  • dom/Document.h:
  • loader/FrameLoader.cpp:

(WebCore::FrameLoader::scrollToFragmentWithParentBoundary):

  • page/FrameView.cpp:

(WebCore::FrameView::FrameView):
(WebCore::FrameView::reset):
(WebCore::FrameView::safeToPropagateScrollToParent const):

  • page/FrameView.h:

LayoutTests:

Add layout test coverage.

  • http/tests/navigation/fragment-navigation-cross-origin-subframe-no-scrolling-parent-expected.txt: Added.
  • http/tests/navigation/fragment-navigation-cross-origin-subframe-no-scrolling-parent.html: Added.
  • http/tests/navigation/resources/clear-fragment.html: Added.
Location:
trunk
Files:
3 added
7 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r231923 r231935  
     12018-05-17  Chris Dumez  <cdumez@apple.com>
     2
     3        RenderLayer::scrollRectToVisible() should not propagate a subframe's scroll to its cross-origin parent
     4        https://bugs.webkit.org/show_bug.cgi?id=185664
     5        <rdar://problem/36185260>
     6
     7        Reviewed by Simon Fraser.
     8
     9        Add layout test coverage.
     10
     11        * http/tests/navigation/fragment-navigation-cross-origin-subframe-no-scrolling-parent-expected.txt: Added.
     12        * http/tests/navigation/fragment-navigation-cross-origin-subframe-no-scrolling-parent.html: Added.
     13        * http/tests/navigation/resources/clear-fragment.html: Added.
     14
    1152018-05-17  Ryan Haddad  <ryanhaddad@apple.com>
    216
  • trunk/Source/WebCore/ChangeLog

    r231932 r231935  
     12018-05-17  Chris Dumez  <cdumez@apple.com>
     2
     3        RenderLayer::scrollRectToVisible() should not propagate a subframe's scroll to its cross-origin parent
     4        https://bugs.webkit.org/show_bug.cgi?id=185664
     5        <rdar://problem/36185260>
     6
     7        Reviewed by Simon Fraser.
     8
     9        RenderLayer::scrollRectToVisible() should not propagate a subframe's scroll to its
     10        cross-origin parent. There was logic in FrameLoader::scrollToFragmentWithParentBoundary()
     11        to temporarily set the 'safeToPropagateScrollToParent' flag to false on the cross-origin
     12        ancestor frame during the call to FrameView::scrollToFragment(). This would correctly
     13        prevent RenderLayer::scrollRectToVisible() to propagate the scroll to the cross-origin
     14        ancestor frame when scrollRectToVisible() is called synchronously. However,
     15        scrollRectToVisible() can get called asynchronously in case of a dirty layout, as part
     16        of the post layout tasks.
     17
     18        To address the issue, we get rid of the safeToPropagateScrollToParent flag on FrameView
     19        and instead update FrameView::safeToPropagateScrollToParent() to do the cross-origin
     20        check. FrameView::safeToPropagateScrollToParent() is called by RenderLayer::scrollRectToVisible()
     21        and this is a lot more robust than relying on a flag which gets temporarily set.
     22
     23        Test: http/tests/navigation/fragment-navigation-cross-origin-subframe-no-scrolling-parent.html
     24
     25        * dom/Document.cpp:
     26        * dom/Document.h:
     27        * loader/FrameLoader.cpp:
     28        (WebCore::FrameLoader::scrollToFragmentWithParentBoundary):
     29        * page/FrameView.cpp:
     30        (WebCore::FrameView::FrameView):
     31        (WebCore::FrameView::reset):
     32        (WebCore::FrameView::safeToPropagateScrollToParent const):
     33        * page/FrameView.h:
     34
    1352018-05-17  Don Olmstead  <don.olmstead@sony.com>
    236
  • trunk/Source/WebCore/dom/Document.cpp

    r231915 r231935  
    32653265}
    32663266
    3267 Frame* Document::findUnsafeParentScrollPropagationBoundary()
    3268 {
    3269     Frame* currentFrame = m_frame;
    3270     if (!currentFrame)
    3271         return nullptr;
    3272 
    3273     Frame* ancestorFrame = currentFrame->tree().parent();
    3274 
    3275     while (ancestorFrame) {
    3276         if (!ancestorFrame->document()->securityOrigin().canAccess(securityOrigin()))
    3277             return currentFrame;
    3278         currentFrame = ancestorFrame;
    3279         ancestorFrame = ancestorFrame->tree().parent();
    3280     }
    3281     return nullptr;
    3282 }
    3283 
    32843267void Document::didRemoveAllPendingStylesheet()
    32853268{
  • trunk/Source/WebCore/dom/Document.h

    r231915 r231935  
    676676
    677677    bool canNavigate(Frame* targetFrame);
    678     Frame* findUnsafeParentScrollPropagationBoundary();
    679678
    680679    bool usesStyleBasedEditability() const;
  • trunk/Source/WebCore/loader/FrameLoader.cpp

    r231779 r231935  
    30293029        return;
    30303030
    3031     // Leaking scroll position to a cross-origin ancestor would permit the so-called "framesniffing" attack.
    3032     RefPtr<Frame> boundaryFrame(url.hasFragmentIdentifier() ? m_frame.document()->findUnsafeParentScrollPropagationBoundary() : 0);
    3033 
    3034     if (boundaryFrame)
    3035         boundaryFrame->view()->setSafeToPropagateScrollToParent(false);
    3036 
    30373031    if (isSameDocumentReload(isNewNavigation, m_loadType) || itemAllowsScrollRestoration(history().currentItem()))
    30383032        view->scrollToFragment(url);
    3039 
    3040     if (boundaryFrame)
    3041         boundaryFrame->view()->setSafeToPropagateScrollToParent(true);
    30423033}
    30433034
  • trunk/Source/WebCore/page/FrameView.cpp

    r231798 r231935  
    180180    , m_wasScrolledByUser(false)
    181181    , m_inProgrammaticScroll(false)
    182     , m_safeToPropagateScrollToParent(true)
    183182    , m_delayedScrollEventTimer(*this, &FrameView::sendScrollEvent)
    184183    , m_selectionRevealModeForFocusedElement(SelectionRevealMode::DoNotReveal)
     
    265264    m_firstLayoutCallbackPending = false;
    266265    m_wasScrolledByUser = false;
    267     m_safeToPropagateScrollToParent = true;
    268266    m_delayedScrollEventTimer.stop();
    269267    m_shouldScrollToFocusedElement = false;
     
    30583056        return false;
    30593057    return true;
     3058}
     3059
     3060bool FrameView::safeToPropagateScrollToParent() const
     3061{
     3062    auto* document = frame().document();
     3063    if (!document)
     3064        return false;
     3065
     3066    auto* parentFrame = frame().tree().parent();
     3067    if (!parentFrame)
     3068        return false;
     3069
     3070    auto* parentDocument = parentFrame->document();
     3071    if (!parentDocument)
     3072        return false;
     3073
     3074    return document->securityOrigin().canAccess(parentDocument->securityOrigin());
    30603075}
    30613076
  • trunk/Source/WebCore/page/FrameView.h

    r230966 r231935  
    338338    WEBCORE_EXPORT void setWasScrolledByUser(bool);
    339339
    340     bool safeToPropagateScrollToParent() const { return m_safeToPropagateScrollToParent; }
    341     void setSafeToPropagateScrollToParent(bool isSafe) { m_safeToPropagateScrollToParent = isSafe; }
     340    bool safeToPropagateScrollToParent() const;
    342341
    343342    void addEmbeddedObjectToUpdate(RenderEmbeddedObject&);
     
    824823    bool m_wasScrolledByUser;
    825824    bool m_inProgrammaticScroll;
    826     bool m_safeToPropagateScrollToParent;
    827825    Timer m_delayedScrollEventTimer;
    828826    bool m_shouldScrollToFocusedElement { false };
Note: See TracChangeset for help on using the changeset viewer.