Changeset 257503 in webkit


Ignore:
Timestamp:
Feb 26, 2020 12:57:49 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

    r257487 r257503  
     12020-02-26  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-26  Daniel Bates  <dabates@apple.com>
    247
  • trunk/Source/WebKit/WebProcess/InjectedBundle/DOM/InjectedBundleNodeHandle.cpp

    r257483 r257503  
    8585Ref<InjectedBundleNodeHandle> InjectedBundleNodeHandle::getOrCreate(Node& node)
    8686{
    87     DOMNodeHandleCache::AddResult result = domNodeHandleCache().add(&node, nullptr);
    88     if (!result.isNewEntry)
    89         return Ref<InjectedBundleNodeHandle>(*result.iterator->value);
    90 
    91     Ref<InjectedBundleNodeHandle> nodeHandle = InjectedBundleNodeHandle::create(node);
    92     result.iterator->value = nodeHandle.ptr();
     87    if (auto* existingHandle = domNodeHandleCache().get(&node))
     88        return Ref<InjectedBundleNodeHandle>(*existingHandle);
     89
     90    auto nodeHandle = InjectedBundleNodeHandle::create(node);
     91    if (nodeHandle->coreNode())
     92        domNodeHandleCache().add(nodeHandle->coreNode(), nodeHandle.ptr());
    9393    return nodeHandle;
    9494}
     
    9696Ref<InjectedBundleNodeHandle> InjectedBundleNodeHandle::create(Node& node)
    9797{
    98     return adoptRef(*new InjectedBundleNodeHandle(node));
     98    auto handle = adoptRef(*new InjectedBundleNodeHandle(node));
     99    handle->suspendIfNeeded();
     100    return handle;
    99101}
    100102
    101103InjectedBundleNodeHandle::InjectedBundleNodeHandle(Node& node)
    102     : m_node(node)
     104    : ActiveDOMObject(node.document())
     105    , m_node(&node)
    103106{
    104107}
     
    106109InjectedBundleNodeHandle::~InjectedBundleNodeHandle()
    107110{
    108     domNodeHandleCache().remove(m_node.ptr());
     111    if (m_node)
     112        domNodeHandleCache().remove(m_node.get());
    109113}
    110114
    111115Node* InjectedBundleNodeHandle::coreNode()
    112116{
    113     return m_node.ptr();
    114 }
    115 
    116 Ref<InjectedBundleNodeHandle> InjectedBundleNodeHandle::document()
    117 {
     117    return m_node.get();
     118}
     119
     120RefPtr<InjectedBundleNodeHandle> InjectedBundleNodeHandle::document()
     121{
     122    if (!m_node)
     123        return nullptr;
     124
    118125    return getOrCreate(m_node->document());
    119126}
     
    127134        return IntRect();
    128135
    129     return downcast<Element>(m_node.get()).boundsInRootViewSpace();
     136    return downcast<Element>(*m_node).boundsInRootViewSpace();
    130137}
    131138   
    132139IntRect InjectedBundleNodeHandle::renderRect(bool* isReplaced)
    133140{
     141    if (!m_node)
     142        return { };
     143
    134144    return m_node->pixelSnappedRenderRect(isReplaced);
    135145}
     
    189199RefPtr<WebImage> InjectedBundleNodeHandle::renderedImage(SnapshotOptions options, bool shouldExcludeOverflow, const Optional<float>& bitmapWidth)
    190200{
     201    if (!m_node)
     202        return nullptr;
     203
    191204    Frame* frame = m_node->document().frame();
    192205    if (!frame)
     
    211224    }
    212225
    213     frameView->setNodeToDraw(m_node.ptr());
     226    frameView->setNodeToDraw(m_node.get());
    214227    auto image = imageForRect(frameView, paintingRect, bitmapWidth, options);
    215228    frameView->setNodeToDraw(0);
     
    220233RefPtr<InjectedBundleRangeHandle> InjectedBundleNodeHandle::visibleRange()
    221234{
    222     VisiblePosition start = firstPositionInNode(m_node.ptr());
    223     VisiblePosition end = lastPositionInNode(m_node.ptr());
     235    if (!m_node)
     236        return nullptr;
     237
     238    VisiblePosition start = firstPositionInNode(m_node.get());
     239    VisiblePosition end = lastPositionInNode(m_node.get());
    224240
    225241    RefPtr<Range> range = makeRange(start, end);
     
    232248        return;
    233249
    234     downcast<HTMLInputElement>(m_node.get()).setValueForUser(value);
     250    downcast<HTMLInputElement>(*m_node).setValueForUser(value);
    235251}
    236252
     
    240256        return;
    241257
    242     downcast<HTMLInputElement>(m_node.get()).setSpellcheckDisabledExceptTextReplacement(!enabled);
     258    downcast<HTMLInputElement>(*m_node).setSpellcheckDisabledExceptTextReplacement(!enabled);
    243259}
    244260
     
    248264        return false;
    249265   
    250     return downcast<HTMLInputElement>(m_node.get()).isAutoFilled();
     266    return downcast<HTMLInputElement>(*m_node).isAutoFilled();
    251267}
    252268
     
    256272        return false;
    257273
    258     return downcast<HTMLInputElement>(m_node.get()).isAutoFilledAndViewable();
     274    return downcast<HTMLInputElement>(*m_node).isAutoFilledAndViewable();
    259275}
    260276
     
    264280        return;
    265281
    266     downcast<HTMLInputElement>(m_node.get()).setAutoFilled(filled);
     282    downcast<HTMLInputElement>(*m_node).setAutoFilled(filled);
    267283}
    268284
     
    272288        return;
    273289
    274     downcast<HTMLInputElement>(m_node.get()).setAutoFilledAndViewable(autoFilledAndViewable);
     290    downcast<HTMLInputElement>(*m_node).setAutoFilledAndViewable(autoFilledAndViewable);
    275291}
    276292
     
    280296        return false;
    281297   
    282     return downcast<HTMLInputElement>(m_node.get()).autoFillButtonType() != AutoFillButtonType::None;
     298    return downcast<HTMLInputElement>(*m_node).autoFillButtonType() != AutoFillButtonType::None;
    283299}
    284300
     
    288304        return;
    289305
    290     downcast<HTMLInputElement>(m_node.get()).setShowAutoFillButton(autoFillButtonType);
     306    downcast<HTMLInputElement>(*m_node).setShowAutoFillButton(autoFillButtonType);
    291307}
    292308
     
    295311    if (!is<HTMLInputElement>(m_node))
    296312        return AutoFillButtonType::None;
    297     return downcast<HTMLInputElement>(m_node.get()).autoFillButtonType();
     313    return downcast<HTMLInputElement>(*m_node).autoFillButtonType();
    298314}
    299315
     
    302318    if (!is<HTMLInputElement>(m_node))
    303319        return AutoFillButtonType::None;
    304     return downcast<HTMLInputElement>(m_node.get()).lastAutoFillButtonType();
     320    return downcast<HTMLInputElement>(*m_node).lastAutoFillButtonType();
    305321}
    306322
     
    310326        return false;
    311327
    312     return downcast<HTMLInputElement>(m_node.get()).isAutoFillAvailable();
     328    return downcast<HTMLInputElement>(*m_node).isAutoFillAvailable();
    313329}
    314330
     
    318334        return;
    319335
    320     downcast<HTMLInputElement>(m_node.get()).setAutoFillAvailable(autoFillAvailable);
     336    downcast<HTMLInputElement>(*m_node).setAutoFillAvailable(autoFillAvailable);
    321337}
    322338
     
    326342        return IntRect();
    327343
    328     auto autoFillButton = downcast<HTMLInputElement>(m_node.get()).autoFillButtonElement();
     344    auto autoFillButton = downcast<HTMLInputElement>(*m_node).autoFillButtonElement();
    329345    if (!autoFillButton)
    330346        return IntRect();
     
    338354        return false;
    339355
    340     return downcast<HTMLInputElement>(m_node.get()).lastChangeWasUserEdit();
     356    return downcast<HTMLInputElement>(*m_node).lastChangeWasUserEdit();
    341357}
    342358
     
    346362        return false;
    347363
    348     return downcast<HTMLTextAreaElement>(m_node.get()).lastChangeWasUserEdit();
     364    return downcast<HTMLTextAreaElement>(*m_node).lastChangeWasUserEdit();
    349365}
    350366
     
    354370        return false;
    355371
    356     return downcast<HTMLInputElement>(m_node.get()).isTextField();
     372    return downcast<HTMLInputElement>(*m_node).isTextField();
    357373}
    358374
     
    367383        return nullptr;
    368384
    369     return getOrCreate(downcast<HTMLTableCellElement>(m_node.get()).cellAbove());
     385    return getOrCreate(downcast<HTMLTableCellElement>(*m_node).cellAbove());
    370386}
    371387
    372388RefPtr<WebFrame> InjectedBundleNodeHandle::documentFrame()
    373389{
    374     if (!m_node->isDocumentNode())
    375         return nullptr;
    376 
    377     Frame* frame = downcast<Document>(m_node.get()).frame();
     390    if (!m_node || !m_node->isDocumentNode())
     391        return nullptr;
     392
     393    Frame* frame = downcast<Document>(*m_node).frame();
    378394    if (!frame)
    379395        return nullptr;
     
    387403        return nullptr;
    388404
    389     Frame* frame = downcast<HTMLFrameElement>(m_node.get()).contentFrame();
     405    Frame* frame = downcast<HTMLFrameElement>(*m_node).contentFrame();
    390406    if (!frame)
    391407        return nullptr;
     
    399415        return nullptr;
    400416
    401     Frame* frame = downcast<HTMLIFrameElement>(m_node.get()).contentFrame();
     417    Frame* frame = downcast<HTMLIFrameElement>(*m_node).contentFrame();
    402418    if (!frame)
    403419        return nullptr;
     
    406422}
    407423
     424void InjectedBundleNodeHandle::stop()
     425{
     426    // Invalidate handles to nodes inside documents that are about to be destroyed in order to prevent leaks.
     427    if (m_node) {
     428        domNodeHandleCache().remove(m_node.get());
     429        m_node = nullptr;
     430    }
     431}
     432
     433const char* InjectedBundleNodeHandle::activeDOMObjectName() const
     434{
     435    return "InjectedBundleNodeHandle";
     436}
     437
    408438} // namespace WebKit
  • trunk/Source/WebKit/WebProcess/InjectedBundle/DOM/InjectedBundleNodeHandle.h

    r257482 r257503  
    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.