Changeset 257389 in webkit


Ignore:
Timestamp:
Feb 25, 2020 4:20:21 PM (4 years ago)
Author:
Chris Dumez
Message:

Make sure a client cannot cause a whole DOM tree to get leaked by simply holding on to a WKBundleNodeHandle
https://bugs.webkit.org/show_bug.cgi?id=208218

Reviewed by Ryosuke Niwa.

Make sure a client cannot cause a whole DOM tree to get leaked by simply holding on to a WKBundleNodeHandle.
Previously, WKBundleNodeHandle would ref its node, which would keep the whole HTML document alive. To protect
against this, InjectedBundleNodeHandle is now an ActiveDOMObject which nulls out its node RefPtr when the
document is getting ready for destruction (i.e. ActiveDOMObject::stop() is called).

  • WebProcess/InjectedBundle/DOM/InjectedBundleNodeHandle.cpp:

(WebKit::InjectedBundleNodeHandle::InjectedBundleNodeHandle):
(WebKit::InjectedBundleNodeHandle::~InjectedBundleNodeHandle):
(WebKit::InjectedBundleNodeHandle::coreNode):
(WebKit::InjectedBundleNodeHandle::document):
(WebKit::InjectedBundleNodeHandle::elementBounds):
(WebKit::InjectedBundleNodeHandle::renderRect):
(WebKit::InjectedBundleNodeHandle::renderedImage):
(WebKit::InjectedBundleNodeHandle::visibleRange):
(WebKit::InjectedBundleNodeHandle::setHTMLInputElementValueForUser):
(WebKit::InjectedBundleNodeHandle::setHTMLInputElementSpellcheckEnabled):
(WebKit::InjectedBundleNodeHandle::isHTMLInputElementAutoFilled const):
(WebKit::InjectedBundleNodeHandle::isHTMLInputElementAutoFilledAndViewable const):
(WebKit::InjectedBundleNodeHandle::setHTMLInputElementAutoFilled):
(WebKit::InjectedBundleNodeHandle::setHTMLInputElementAutoFilledAndViewable):
(WebKit::InjectedBundleNodeHandle::isHTMLInputElementAutoFillButtonEnabled const):
(WebKit::InjectedBundleNodeHandle::setHTMLInputElementAutoFillButtonEnabled):
(WebKit::InjectedBundleNodeHandle::htmlInputElementAutoFillButtonType const):
(WebKit::InjectedBundleNodeHandle::htmlInputElementLastAutoFillButtonType const):
(WebKit::InjectedBundleNodeHandle::isAutoFillAvailable const):
(WebKit::InjectedBundleNodeHandle::setAutoFillAvailable):
(WebKit::InjectedBundleNodeHandle::htmlInputElementAutoFillButtonBounds):
(WebKit::InjectedBundleNodeHandle::htmlInputElementLastChangeWasUserEdit):
(WebKit::InjectedBundleNodeHandle::htmlTextAreaElementLastChangeWasUserEdit):
(WebKit::InjectedBundleNodeHandle::isTextField const):
(WebKit::InjectedBundleNodeHandle::htmlTableCellElementCellAbove):
(WebKit::InjectedBundleNodeHandle::documentFrame):
(WebKit::InjectedBundleNodeHandle::htmlFrameElementContentFrame):
(WebKit::InjectedBundleNodeHandle::htmlIFrameElementContentFrame):
(WebKit::InjectedBundleNodeHandle::stop):
(WebKit::InjectedBundleNodeHandle::activeDOMObjectName const):

  • WebProcess/InjectedBundle/DOM/InjectedBundleNodeHandle.h:
Location:
trunk/Source/WebKit
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebKit/ChangeLog

    r257386 r257389  
     12020-02-25  Chris Dumez  <cdumez@apple.com>
     2
     3        Make sure a client cannot cause a whole DOM tree to get leaked by simply holding on to a WKBundleNodeHandle
     4        https://bugs.webkit.org/show_bug.cgi?id=208218
     5
     6        Reviewed by Ryosuke Niwa.
     7
     8        Make sure a client cannot cause a whole DOM tree to get leaked by simply holding on to a WKBundleNodeHandle.
     9        Previously, WKBundleNodeHandle would ref its node, which would keep the whole HTML document alive. To protect
     10        against this, InjectedBundleNodeHandle is now an ActiveDOMObject which nulls out its node RefPtr when the
     11        document is getting ready for destruction (i.e. ActiveDOMObject::stop() is called).
     12
     13        * WebProcess/InjectedBundle/DOM/InjectedBundleNodeHandle.cpp:
     14        (WebKit::InjectedBundleNodeHandle::InjectedBundleNodeHandle):
     15        (WebKit::InjectedBundleNodeHandle::~InjectedBundleNodeHandle):
     16        (WebKit::InjectedBundleNodeHandle::coreNode):
     17        (WebKit::InjectedBundleNodeHandle::document):
     18        (WebKit::InjectedBundleNodeHandle::elementBounds):
     19        (WebKit::InjectedBundleNodeHandle::renderRect):
     20        (WebKit::InjectedBundleNodeHandle::renderedImage):
     21        (WebKit::InjectedBundleNodeHandle::visibleRange):
     22        (WebKit::InjectedBundleNodeHandle::setHTMLInputElementValueForUser):
     23        (WebKit::InjectedBundleNodeHandle::setHTMLInputElementSpellcheckEnabled):
     24        (WebKit::InjectedBundleNodeHandle::isHTMLInputElementAutoFilled const):
     25        (WebKit::InjectedBundleNodeHandle::isHTMLInputElementAutoFilledAndViewable const):
     26        (WebKit::InjectedBundleNodeHandle::setHTMLInputElementAutoFilled):
     27        (WebKit::InjectedBundleNodeHandle::setHTMLInputElementAutoFilledAndViewable):
     28        (WebKit::InjectedBundleNodeHandle::isHTMLInputElementAutoFillButtonEnabled const):
     29        (WebKit::InjectedBundleNodeHandle::setHTMLInputElementAutoFillButtonEnabled):
     30        (WebKit::InjectedBundleNodeHandle::htmlInputElementAutoFillButtonType const):
     31        (WebKit::InjectedBundleNodeHandle::htmlInputElementLastAutoFillButtonType const):
     32        (WebKit::InjectedBundleNodeHandle::isAutoFillAvailable const):
     33        (WebKit::InjectedBundleNodeHandle::setAutoFillAvailable):
     34        (WebKit::InjectedBundleNodeHandle::htmlInputElementAutoFillButtonBounds):
     35        (WebKit::InjectedBundleNodeHandle::htmlInputElementLastChangeWasUserEdit):
     36        (WebKit::InjectedBundleNodeHandle::htmlTextAreaElementLastChangeWasUserEdit):
     37        (WebKit::InjectedBundleNodeHandle::isTextField const):
     38        (WebKit::InjectedBundleNodeHandle::htmlTableCellElementCellAbove):
     39        (WebKit::InjectedBundleNodeHandle::documentFrame):
     40        (WebKit::InjectedBundleNodeHandle::htmlFrameElementContentFrame):
     41        (WebKit::InjectedBundleNodeHandle::htmlIFrameElementContentFrame):
     42        (WebKit::InjectedBundleNodeHandle::stop):
     43        (WebKit::InjectedBundleNodeHandle::activeDOMObjectName const):
     44        * WebProcess/InjectedBundle/DOM/InjectedBundleNodeHandle.h:
     45
    1462020-02-25  Youenn Fablet  <youenn@apple.com>
    247
  • trunk/Source/WebKit/WebProcess/InjectedBundle/DOM/InjectedBundleNodeHandle.cpp

    r249175 r257389  
    100100
    101101InjectedBundleNodeHandle::InjectedBundleNodeHandle(Node& node)
    102     : m_node(node)
     102    : ActiveDOMObject(node.document())
     103    , m_node(&node)
    103104{
    104105}
     
    106107InjectedBundleNodeHandle::~InjectedBundleNodeHandle()
    107108{
    108     domNodeHandleCache().remove(m_node.ptr());
     109    if (m_node)
     110        domNodeHandleCache().remove(m_node.get());
    109111}
    110112
    111113Node* InjectedBundleNodeHandle::coreNode()
    112114{
    113     return m_node.ptr();
    114 }
    115 
    116 Ref<InjectedBundleNodeHandle> InjectedBundleNodeHandle::document()
    117 {
     115    return m_node.get();
     116}
     117
     118RefPtr<InjectedBundleNodeHandle> InjectedBundleNodeHandle::document()
     119{
     120    if (!m_node)
     121        return nullptr;
     122
    118123    return getOrCreate(m_node->document());
    119124}
     
    127132        return IntRect();
    128133
    129     return downcast<Element>(m_node.get()).boundsInRootViewSpace();
     134    return downcast<Element>(*m_node).boundsInRootViewSpace();
    130135}
    131136   
    132137IntRect InjectedBundleNodeHandle::renderRect(bool* isReplaced)
    133138{
     139    if (!m_node)
     140        return { };
     141
    134142    return m_node->pixelSnappedRenderRect(isReplaced);
    135143}
     
    189197RefPtr<WebImage> InjectedBundleNodeHandle::renderedImage(SnapshotOptions options, bool shouldExcludeOverflow, const Optional<float>& bitmapWidth)
    190198{
     199    if (!m_node)
     200        return nullptr;
     201
    191202    Frame* frame = m_node->document().frame();
    192203    if (!frame)
     
    211222    }
    212223
    213     frameView->setNodeToDraw(m_node.ptr());
     224    frameView->setNodeToDraw(m_node.get());
    214225    auto image = imageForRect(frameView, paintingRect, bitmapWidth, options);
    215226    frameView->setNodeToDraw(0);
     
    220231RefPtr<InjectedBundleRangeHandle> InjectedBundleNodeHandle::visibleRange()
    221232{
    222     VisiblePosition start = firstPositionInNode(m_node.ptr());
    223     VisiblePosition end = lastPositionInNode(m_node.ptr());
     233    if (!m_node)
     234        return nullptr;
     235
     236    VisiblePosition start = firstPositionInNode(m_node.get());
     237    VisiblePosition end = lastPositionInNode(m_node.get());
    224238
    225239    RefPtr<Range> range = makeRange(start, end);
     
    232246        return;
    233247
    234     downcast<HTMLInputElement>(m_node.get()).setValueForUser(value);
     248    downcast<HTMLInputElement>(*m_node).setValueForUser(value);
    235249}
    236250
     
    240254        return;
    241255
    242     downcast<HTMLInputElement>(m_node.get()).setSpellcheckDisabledExceptTextReplacement(!enabled);
     256    downcast<HTMLInputElement>(*m_node).setSpellcheckDisabledExceptTextReplacement(!enabled);
    243257}
    244258
     
    248262        return false;
    249263   
    250     return downcast<HTMLInputElement>(m_node.get()).isAutoFilled();
     264    return downcast<HTMLInputElement>(*m_node).isAutoFilled();
    251265}
    252266
     
    256270        return false;
    257271
    258     return downcast<HTMLInputElement>(m_node.get()).isAutoFilledAndViewable();
     272    return downcast<HTMLInputElement>(*m_node).isAutoFilledAndViewable();
    259273}
    260274
     
    264278        return;
    265279
    266     downcast<HTMLInputElement>(m_node.get()).setAutoFilled(filled);
     280    downcast<HTMLInputElement>(*m_node).setAutoFilled(filled);
    267281}
    268282
     
    272286        return;
    273287
    274     downcast<HTMLInputElement>(m_node.get()).setAutoFilledAndViewable(autoFilledAndViewable);
     288    downcast<HTMLInputElement>(*m_node).setAutoFilledAndViewable(autoFilledAndViewable);
    275289}
    276290
     
    280294        return false;
    281295   
    282     return downcast<HTMLInputElement>(m_node.get()).autoFillButtonType() != AutoFillButtonType::None;
     296    return downcast<HTMLInputElement>(*m_node).autoFillButtonType() != AutoFillButtonType::None;
    283297}
    284298
     
    288302        return;
    289303
    290     downcast<HTMLInputElement>(m_node.get()).setShowAutoFillButton(autoFillButtonType);
     304    downcast<HTMLInputElement>(*m_node).setShowAutoFillButton(autoFillButtonType);
    291305}
    292306
     
    295309    if (!is<HTMLInputElement>(m_node))
    296310        return AutoFillButtonType::None;
    297     return downcast<HTMLInputElement>(m_node.get()).autoFillButtonType();
     311    return downcast<HTMLInputElement>(*m_node).autoFillButtonType();
    298312}
    299313
     
    302316    if (!is<HTMLInputElement>(m_node))
    303317        return AutoFillButtonType::None;
    304     return downcast<HTMLInputElement>(m_node.get()).lastAutoFillButtonType();
     318    return downcast<HTMLInputElement>(*m_node).lastAutoFillButtonType();
    305319}
    306320
     
    310324        return false;
    311325
    312     return downcast<HTMLInputElement>(m_node.get()).isAutoFillAvailable();
     326    return downcast<HTMLInputElement>(*m_node).isAutoFillAvailable();
    313327}
    314328
     
    318332        return;
    319333
    320     downcast<HTMLInputElement>(m_node.get()).setAutoFillAvailable(autoFillAvailable);
     334    downcast<HTMLInputElement>(*m_node).setAutoFillAvailable(autoFillAvailable);
    321335}
    322336
     
    326340        return IntRect();
    327341
    328     auto autoFillButton = downcast<HTMLInputElement>(m_node.get()).autoFillButtonElement();
     342    auto autoFillButton = downcast<HTMLInputElement>(*m_node).autoFillButtonElement();
    329343    if (!autoFillButton)
    330344        return IntRect();
     
    338352        return false;
    339353
    340     return downcast<HTMLInputElement>(m_node.get()).lastChangeWasUserEdit();
     354    return downcast<HTMLInputElement>(*m_node).lastChangeWasUserEdit();
    341355}
    342356
     
    346360        return false;
    347361
    348     return downcast<HTMLTextAreaElement>(m_node.get()).lastChangeWasUserEdit();
     362    return downcast<HTMLTextAreaElement>(*m_node).lastChangeWasUserEdit();
    349363}
    350364
     
    354368        return false;
    355369
    356     return downcast<HTMLInputElement>(m_node.get()).isTextField();
     370    return downcast<HTMLInputElement>(*m_node).isTextField();
    357371}
    358372
     
    367381        return nullptr;
    368382
    369     return getOrCreate(downcast<HTMLTableCellElement>(m_node.get()).cellAbove());
     383    return getOrCreate(downcast<HTMLTableCellElement>(*m_node).cellAbove());
    370384}
    371385
    372386RefPtr<WebFrame> InjectedBundleNodeHandle::documentFrame()
    373387{
    374     if (!m_node->isDocumentNode())
    375         return nullptr;
    376 
    377     Frame* frame = downcast<Document>(m_node.get()).frame();
     388    if (!m_node || !m_node->isDocumentNode())
     389        return nullptr;
     390
     391    Frame* frame = downcast<Document>(*m_node).frame();
    378392    if (!frame)
    379393        return nullptr;
     
    387401        return nullptr;
    388402
    389     Frame* frame = downcast<HTMLFrameElement>(m_node.get()).contentFrame();
     403    Frame* frame = downcast<HTMLFrameElement>(*m_node).contentFrame();
    390404    if (!frame)
    391405        return nullptr;
     
    399413        return nullptr;
    400414
    401     Frame* frame = downcast<HTMLIFrameElement>(m_node.get()).contentFrame();
     415    Frame* frame = downcast<HTMLIFrameElement>(*m_node).contentFrame();
    402416    if (!frame)
    403417        return nullptr;
     
    406420}
    407421
     422void InjectedBundleNodeHandle::stop()
     423{
     424    // Invalidate handles to nodes inside documents that are about to be destroyed in order to prevent leaks.
     425    if (m_node) {
     426        domNodeHandleCache().remove(m_node.get());
     427        m_node = nullptr;
     428    }
     429}
     430
     431const char* InjectedBundleNodeHandle::activeDOMObjectName() const
     432{
     433    return "InjectedBundleNodeHandle";
     434}
     435
    408436} // namespace WebKit
  • trunk/Source/WebKit/WebProcess/InjectedBundle/DOM/InjectedBundleNodeHandle.h

    r248373 r257389  
    2929#include "ImageOptions.h"
    3030#include <JavaScriptCore/JSBase.h>
     31#include <WebCore/ActiveDOMObject.h>
    3132#include <wtf/Forward.h>
    3233#include <wtf/Optional.h>
     
    4647class WebImage;
    4748
    48 class InjectedBundleNodeHandle : public API::ObjectImpl<API::Object::Type::BundleNodeHandle> {
     49class InjectedBundleNodeHandle : public API::ObjectImpl<API::Object::Type::BundleNodeHandle>, public WebCore::ActiveDOMObject {
    4950public:
    5051    static RefPtr<InjectedBundleNodeHandle> getOrCreate(JSContextRef, JSObjectRef);
     
    5758
    5859    // Convenience DOM Operations
    59     Ref<InjectedBundleNodeHandle> document();
     60    RefPtr<InjectedBundleNodeHandle> document();
    6061
    6162    // Additional DOM Operations
     
    9394    InjectedBundleNodeHandle(WebCore::Node&);
    9495
    95     Ref<WebCore::Node> m_node;
     96    // ActiveDOMObject.
     97    void stop() final;
     98    const char* activeDOMObjectName() const final;
     99
     100    RefPtr<WebCore::Node> m_node;
    96101};
    97102
Note: See TracChangeset for help on using the changeset viewer.