Changeset 249762 in webkit


Ignore:
Timestamp:
Sep 11, 2019 7:52:18 AM (5 years ago)
Author:
ajuma@chromium.org
Message:

Prevent reentrancy FrameLoader::dispatchUnloadEvents()
https://bugs.webkit.org/show_bug.cgi?id=200738

Reviewed by Brady Eidson.

Reentrancy causes m_pageDismissalEventBeingDispatched to be incorrectly
updated, so don't allow reentrancy.

Since this prevents m_pageDismissalEventBeingDispatched from being reset
inside a reentrant call, it can have the unintended effect of causing
FrameLoader::stopAllLoaders to early-out when called from
FrameLoader::detachFromParent while a frame's unload event handler
calls document.open() on a parent frame and causes itself to become
detached. Allowing a load to continue in a detached frame will lead to
a crash. To prevent this, add a new argument to FrameLoader::stopAllLoaders
that FrameLoader::detachFromParent can use to prevent an early-out.

  • loader/FrameLoader.cpp:

(WebCore::FrameLoader::stopAllLoaders):
(WebCore::FrameLoader::detachFromParent):
(WebCore::FrameLoader::dispatchUnloadEvents):
(WebCore::FrameLoader::dispatchBeforeUnloadEvent):
Ensure that m_pageDismissalEventBeingDispatched is reset to its previous value, even if this is not None.

  • loader/FrameLoader.h:
  • loader/FrameLoaderTypes.h:

Add a StopLoadingPolicy enum.

Location:
trunk/Source/WebCore
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r249761 r249762  
     12019-09-11  Ali Juma  <ajuma@chromium.org>
     2
     3        Prevent reentrancy FrameLoader::dispatchUnloadEvents()
     4        https://bugs.webkit.org/show_bug.cgi?id=200738
     5
     6        Reviewed by Brady Eidson.
     7
     8        Reentrancy causes m_pageDismissalEventBeingDispatched to be incorrectly
     9        updated, so don't allow reentrancy.
     10
     11        Since this prevents m_pageDismissalEventBeingDispatched from being reset
     12        inside a reentrant call, it can have the unintended effect of causing
     13        FrameLoader::stopAllLoaders to early-out when called from
     14        FrameLoader::detachFromParent while a frame's unload event handler
     15        calls document.open() on a parent frame and causes itself to become
     16        detached. Allowing a load to continue in a detached frame will lead to
     17        a crash. To prevent this, add a new argument to FrameLoader::stopAllLoaders
     18        that FrameLoader::detachFromParent can use to prevent an early-out.
     19
     20        * loader/FrameLoader.cpp:
     21        (WebCore::FrameLoader::stopAllLoaders):
     22        (WebCore::FrameLoader::detachFromParent):
     23        (WebCore::FrameLoader::dispatchUnloadEvents):
     24        (WebCore::FrameLoader::dispatchBeforeUnloadEvent):
     25        Ensure that m_pageDismissalEventBeingDispatched is reset to its previous value, even if this is not None.
     26        * loader/FrameLoader.h:
     27        * loader/FrameLoaderTypes.h:
     28        Add a StopLoadingPolicy enum.
     29
    1302019-09-11  Charlie Turner  <cturner@igalia.com>
    231
  • trunk/Source/WebCore/loader/FrameLoader.cpp

    r249452 r249762  
    18071807}
    18081808
    1809 void FrameLoader::stopAllLoaders(ClearProvisionalItemPolicy clearProvisionalItemPolicy)
     1809void FrameLoader::stopAllLoaders(ClearProvisionalItemPolicy clearProvisionalItemPolicy, StopLoadingPolicy stopLoadingPolicy)
    18101810{
    18111811    if (m_frame.document() && m_frame.document()->pageCacheState() == Document::InPageCache)
    18121812        return;
    18131813
    1814     if (!isStopLoadingAllowed())
     1814    if (stopLoadingPolicy == StopLoadingPolicy::PreventDuringUnloadEvents && !isStopLoadingAllowed())
    18151815        return;
    18161816
     
    28212821        // because detachedChildren() will trigger the unload event handlers of any child frames, and those event
    28222822        // handlers might start a new subresource load in this frame.
    2823         stopAllLoaders();
     2823        stopAllLoaders(ShouldClearProvisionalItem, StopLoadingPolicy::AlwaysStopLoading);
    28242824    }
    28252825
     
    32723272{
    32733273    if (!m_frame.document())
     3274        return;
     3275
     3276    if (m_pageDismissalEventBeingDispatched != PageDismissalType::None)
    32743277        return;
    32753278
     
    33523355   
    33533356    Ref<BeforeUnloadEvent> beforeUnloadEvent = BeforeUnloadEvent::create();
    3354     m_pageDismissalEventBeingDispatched = PageDismissalType::BeforeUnload;
    33553357
    33563358    {
     3359        SetForScope<PageDismissalType> change(m_pageDismissalEventBeingDispatched, PageDismissalType::BeforeUnload);
    33573360        ForbidPromptsScope forbidPrompts(m_frame.page());
    33583361        domWindow->dispatchEvent(beforeUnloadEvent, domWindow->document());
    33593362    }
    3360 
    3361     m_pageDismissalEventBeingDispatched = PageDismissalType::None;
    33623363
    33633364    if (!beforeUnloadEvent->defaultPrevented())
  • trunk/Source/WebCore/loader/FrameLoader.h

    r248762 r249762  
    146146    // FIXME: These are all functions which stop loads. We have too many.
    147147    void stopAllLoadersAndCheckCompleteness();
    148     WEBCORE_EXPORT void stopAllLoaders(ClearProvisionalItemPolicy = ShouldClearProvisionalItem);
     148    WEBCORE_EXPORT void stopAllLoaders(ClearProvisionalItemPolicy = ShouldClearProvisionalItem, StopLoadingPolicy = StopLoadingPolicy::PreventDuringUnloadEvents);
    149149    WEBCORE_EXPORT void stopForUserCancel(bool deferCheckLoadComplete = false);
    150150    void stop();
  • trunk/Source/WebCore/loader/FrameLoaderTypes.h

    r246701 r249762  
    142142};
    143143
     144enum class StopLoadingPolicy {
     145    PreventDuringUnloadEvents,
     146    AlwaysStopLoading
     147};
     148
    144149enum class ObjectContentType : uint8_t {
    145150    None,
Note: See TracChangeset for help on using the changeset viewer.