Changeset 225878 in webkit


Ignore:
Timestamp:
Dec 13, 2017 4:05:42 PM (6 years ago)
Author:
rniwa@webkit.org
Message:

Crash inside ImageLoader::updateFromElement()
https://bugs.webkit.org/show_bug.cgi?id=180769
<rdar://problem/35278782>

Reviewed by Antti Koivisto.

Fixed the crash by moving all call sites of ImageLoader::updateFromElement() to be post insertion callbacks
where it's safe to execute arbitrary scripts.

No new test since existing tests cover this with a newly added release assert in ImageLoader.

  • html/HTMLImageElement.cpp:

(WebCore::HTMLImageElement::insertedIntoAncestor):
(WebCore::HTMLImageElement::didFinishInsertingNode): Extracted from insertedIntoAncestor to call
selectImageSource or updateFromElement.

  • html/HTMLImageElement.h: Made many member functions final.
  • html/HTMLInputElement.cpp:

(WebCore::HTMLInputElement::didAttachRenderers): Delay the call to ImageLoader::updateFromElement() in
ImageInputType using a post style resolution callback.

  • html/HTMLMetaElement.h:
  • html/HTMLPictureElement.cpp:

(WebCore::HTMLPictureElement::sourcesChanged): Store the list of child image elements into a vector before
calling selectImageSource since each call may execute arbitrary scripts.

  • html/HTMLSourceElement.cpp:

(WebCore::HTMLSourceElement::insertedIntoAncestor): Delay the call to ImageLoader::updateFromElement()
using a post style resolution callback.
(WebCore::HTMLSourceElement::didFinishInsertingNode): Extracted from insertedIntoAncestor.

  • html/HTMLSourceElement.h:
  • html/HTMLVideoElement.cpp:

(WebCore::HTMLVideoElement::didAttachRenderers):
(WebCore::HTMLVideoElement::updateAfterStyleResolution): Extracted from didAttachRenderers.

  • html/HTMLVideoElement.h:
  • html/ImageInputType.cpp:

(WebCore::ImageInputType::needsPostStyleResolutionCallback): Added. Returns true so that HTMLInputElement's
didAttachRenderers would register a post style resolution callback.
(WebCore::ImageInputType::updateAfterStyleResolution): Extracted from attach.
(WebCore::ImageInputType::attach): Deleted.

  • html/ImageInputType.h:
  • html/InputType.cpp:

(WebCore::InputType::needsPostStyleResolutionCallback): Added. All but ImageInputType returns false.
(WebCore::InputType::updateAfterStyleResolution): Added.
(WebCore::InputType::attach): Deleted.

  • html/InputType.h:
  • loader/ImageLoader.cpp:

(WebCore::ImageLoader::updateFromElement): Added a release assertion. There is no direct security implication
so there is no need to use RELEASE_ASSERT_WITH_SECURITY_IMPLICATION here.

  • svg/SVGImageElement.cpp:

(WebCore::SVGImageElement::insertedIntoAncestor):
(WebCore::SVGImageElement::didFinishInsertingNode):

  • svg/SVGImageElement.h:
Location:
trunk/Source/WebCore
Files:
17 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r225872 r225878  
     12017-12-13  Ryosuke Niwa  <rniwa@webkit.org>
     2
     3        Crash inside ImageLoader::updateFromElement()
     4        https://bugs.webkit.org/show_bug.cgi?id=180769
     5        <rdar://problem/35278782>
     6
     7        Reviewed by Antti Koivisto.
     8
     9        Fixed the crash by moving all call sites of ImageLoader::updateFromElement() to be post insertion callbacks
     10        where it's safe to execute arbitrary scripts.
     11
     12        No new test since existing tests cover this with a newly added release assert in ImageLoader.
     13
     14        * html/HTMLImageElement.cpp:
     15        (WebCore::HTMLImageElement::insertedIntoAncestor):
     16        (WebCore::HTMLImageElement::didFinishInsertingNode): Extracted from insertedIntoAncestor to call
     17        selectImageSource or updateFromElement.
     18        * html/HTMLImageElement.h: Made many member functions final.
     19        * html/HTMLInputElement.cpp:
     20        (WebCore::HTMLInputElement::didAttachRenderers): Delay the call to ImageLoader::updateFromElement() in
     21        ImageInputType using a post style resolution callback.
     22        * html/HTMLMetaElement.h:
     23        * html/HTMLPictureElement.cpp:
     24        (WebCore::HTMLPictureElement::sourcesChanged): Store the list of child image elements into a vector before
     25        calling selectImageSource since each call may execute arbitrary scripts.
     26        * html/HTMLSourceElement.cpp:
     27        (WebCore::HTMLSourceElement::insertedIntoAncestor): Delay the call to ImageLoader::updateFromElement()
     28        using a post style resolution callback.
     29        (WebCore::HTMLSourceElement::didFinishInsertingNode): Extracted from insertedIntoAncestor.
     30        * html/HTMLSourceElement.h:
     31        * html/HTMLVideoElement.cpp:
     32        (WebCore::HTMLVideoElement::didAttachRenderers):
     33        (WebCore::HTMLVideoElement::updateAfterStyleResolution): Extracted from didAttachRenderers.
     34        * html/HTMLVideoElement.h:
     35        * html/ImageInputType.cpp:
     36        (WebCore::ImageInputType::needsPostStyleResolutionCallback): Added. Returns true so that HTMLInputElement's
     37        didAttachRenderers would register a post style resolution callback.
     38        (WebCore::ImageInputType::updateAfterStyleResolution): Extracted from attach.
     39        (WebCore::ImageInputType::attach): Deleted.
     40        * html/ImageInputType.h:
     41        * html/InputType.cpp:
     42        (WebCore::InputType::needsPostStyleResolutionCallback): Added. All but ImageInputType returns false.
     43        (WebCore::InputType::updateAfterStyleResolution): Added.
     44        (WebCore::InputType::attach): Deleted.
     45        * html/InputType.h:
     46        * loader/ImageLoader.cpp:
     47        (WebCore::ImageLoader::updateFromElement): Added a release assertion. There is no direct security implication
     48        so there is no need to use RELEASE_ASSERT_WITH_SECURITY_IMPLICATION here.
     49        * svg/SVGImageElement.cpp:
     50        (WebCore::SVGImageElement::insertedIntoAncestor):
     51        (WebCore::SVGImageElement::didFinishInsertingNode):
     52        * svg/SVGImageElement.h:
     53
    1542017-12-13  Zalan Bujtas  <zalan@apple.com>
    255
  • trunk/Source/WebCore/html/HTMLImageElement.cpp

    r225616 r225878  
    296296Node::InsertedIntoAncestorResult HTMLImageElement::insertedIntoAncestor(InsertionType insertionType, ContainerNode& parentOfInsertedTree)
    297297{
     298    HTMLElement::insertedIntoAncestor(insertionType, parentOfInsertedTree);
     299
    298300    if (m_formSetByParser) {
    299301        m_form = m_formSetByParser;
     
    312314            m_form->registerImgElement(this);
    313315    }
    314     // Insert needs to complete first, before we start updating the loader. Loader dispatches events which could result
    315     // in callbacks back to this node.
    316     Node::InsertedIntoAncestorResult insertNotificationRequest = HTMLElement::insertedIntoAncestor(insertionType, parentOfInsertedTree);
    317316
    318317    if (insertionType.connectedToDocument && !m_parsedUsemap.isNull())
     
    321320    if (is<HTMLPictureElement>(parentNode())) {
    322321        setPictureElement(&downcast<HTMLPictureElement>(*parentNode()));
    323         selectImageSource();
     322        return InsertedIntoAncestorResult::NeedsPostInsertionCallback;
    324323    }
    325324
     
    327326    // our loader may have not fetched the image, so do it now.
    328327    if (insertionType.connectedToDocument && !m_imageLoader.image())
     328        return InsertedIntoAncestorResult::NeedsPostInsertionCallback;
     329
     330    return InsertedIntoAncestorResult::Done;
     331}
     332
     333void HTMLImageElement::didFinishInsertingNode()
     334{
     335    if (pictureElement())
     336        selectImageSource();
     337    else if (isConnected())
    329338        m_imageLoader.updateFromElement();
    330 
    331     return insertNotificationRequest;
    332339}
    333340
  • trunk/Source/WebCore/html/HTMLImageElement.h

    r225616 r225878  
    9191    bool hasPendingActivity() const { return m_imageLoader.hasPendingActivity(); }
    9292
    93     bool canContainRangeEndPoint() const override { return false; }
     93    bool canContainRangeEndPoint() const final { return false; }
    9494
    95     const AtomicString& imageSourceURL() const override;
     95    const AtomicString& imageSourceURL() const final;
    9696
    9797    bool hasShadowControls() const { return m_experimentalImageMenuEnabled; }
     
    106106
    107107private:
    108     void parseAttribute(const QualifiedName&, const AtomicString&) override;
    109     bool isPresentationAttribute(const QualifiedName&) const override;
    110     void collectStyleForPresentationAttribute(const QualifiedName&, const AtomicString&, MutableStyleProperties&) override;
     108    void parseAttribute(const QualifiedName&, const AtomicString&) final;
     109    bool isPresentationAttribute(const QualifiedName&) const final;
     110    void collectStyleForPresentationAttribute(const QualifiedName&, const AtomicString&, MutableStyleProperties&) final;
    111111
    112     void didAttachRenderers() override;
    113     RenderPtr<RenderElement> createElementRenderer(RenderStyle&&, const RenderTreePosition&) override;
     112    void didAttachRenderers() final;
     113    RenderPtr<RenderElement> createElementRenderer(RenderStyle&&, const RenderTreePosition&) final;
    114114    void setBestFitURLAndDPRFromImageCandidate(const ImageCandidate&);
    115115
    116     bool canStartSelection() const override;
     116    bool canStartSelection() const final;
    117117
    118     bool isURLAttribute(const Attribute&) const override;
    119     bool attributeContainsURL(const Attribute&) const override;
    120     String completeURLsInAttributeValue(const URL& base, const Attribute&) const override;
     118    bool isURLAttribute(const Attribute&) const final;
     119    bool attributeContainsURL(const Attribute&) const final;
     120    String completeURLsInAttributeValue(const URL& base, const Attribute&) const final;
    121121
    122     bool draggable() const override;
     122    bool draggable() const final;
    123123
    124     void addSubresourceAttributeURLs(ListHashSet<URL>&) const override;
     124    void addSubresourceAttributeURLs(ListHashSet<URL>&) const final;
    125125
    126     InsertedIntoAncestorResult insertedIntoAncestor(InsertionType, ContainerNode&) override;
    127     void removedFromAncestor(RemovalType, ContainerNode&) override;
     126    InsertedIntoAncestorResult insertedIntoAncestor(InsertionType, ContainerNode&) final;
     127    void didFinishInsertingNode() final;
     128    void removedFromAncestor(RemovalType, ContainerNode&) final;
    128129
    129130    bool isFormAssociatedElement() const final { return false; }
     
    153154    void destroyImageControls();
    154155    bool hasImageControls() const;
    155     bool childShouldCreateRenderer(const Node&) const override;
     156    bool childShouldCreateRenderer(const Node&) const final;
    156157#endif
    157158
  • trunk/Source/WebCore/html/HTMLInputElement.cpp

    r225680 r225878  
    5959#include "Settings.h"
    6060#include "StyleResolver.h"
     61#include "StyleTreeResolver.h"
    6162#include "TextControlInnerElements.h"
    6263#include <wtf/Language.h>
     
    846847    HTMLTextFormControlElement::didAttachRenderers();
    847848
    848     m_inputType->attach();
     849    if (m_inputType->needsPostStyleResolutionCallback()) {
     850        Style::queuePostResolutionCallback([protectedElement = makeRef(*this)] {
     851            protectedElement->m_inputType->updateAfterStyleResolution();
     852        });
     853    }
    849854
    850855    if (document().focusedElement() == this) {
  • trunk/Source/WebCore/html/HTMLMetaElement.h

    r225723 r225878  
    4141    void parseAttribute(const QualifiedName&, const AtomicString&) final;
    4242    InsertedIntoAncestorResult insertedIntoAncestor(InsertionType, ContainerNode&) final;
    43     void didFinishInsertingNode();
     43    void didFinishInsertingNode() final;
    4444
    4545    void process();
  • trunk/Source/WebCore/html/HTMLPictureElement.cpp

    r224390 r225878  
    5757void HTMLPictureElement::sourcesChanged()
    5858{
     59    Vector<Ref<HTMLImageElement>, 4> imageElements;
    5960    for (auto& element : childrenOfType<HTMLImageElement>(*this))
    60         element.selectImageSource();
     61        imageElements.append(element);
     62    for (auto& element : imageElements)
     63        element->selectImageSource();
    6164}
    6265
  • trunk/Source/WebCore/html/HTMLSourceElement.cpp

    r224390 r225878  
    7575#endif
    7676        if (is<HTMLPictureElement>(*parent))
    77             downcast<HTMLPictureElement>(*parent).sourcesChanged();
     77            return InsertedIntoAncestorResult::NeedsPostInsertionCallback;
     78
    7879    }
    7980    return InsertedIntoAncestorResult::Done;
     81}
     82
     83void HTMLSourceElement::didFinishInsertingNode()
     84{
     85    auto* parent = parentElement();
     86    if (is<HTMLPictureElement>(*parent))
     87        downcast<HTMLPictureElement>(*parent).sourcesChanged();
    8088}
    8189
  • trunk/Source/WebCore/html/HTMLSourceElement.h

    r223802 r225878  
    4747   
    4848    InsertedIntoAncestorResult insertedIntoAncestor(InsertionType, ContainerNode&) final;
     49    void didFinishInsertingNode() final;
    4950    void removedFromAncestor(RemovalType, ContainerNode&) final;
    5051    bool isURLAttribute(const Attribute&) const final;
  • trunk/Source/WebCore/html/HTMLVideoElement.cpp

    r223960 r225878  
    4444#include "ScriptController.h"
    4545#include "Settings.h"
     46#include "StyleTreeResolver.h"
    4647#include <wtf/text/TextStream.h>
    4748
     
    9192    updateDisplayState();
    9293    if (shouldDisplayPosterImage()) {
    93         if (!m_imageLoader)
    94             m_imageLoader = std::make_unique<HTMLImageLoader>(*this);
    95         m_imageLoader->updateFromElement();
    96         if (auto* renderer = this->renderer())
    97             renderer->imageResource().setCachedImage(m_imageLoader->image());
    98     }
     94        Style::queuePostResolutionCallback([protectedThis = makeRef(*this)] {
     95            protectedThis->updateAfterStyleResolution();
     96        });
     97    }
     98}
     99
     100void HTMLVideoElement::updateAfterStyleResolution()
     101{
     102    if (!m_imageLoader)
     103        m_imageLoader = std::make_unique<HTMLImageLoader>(*this);
     104    m_imageLoader->updateFromElement();
     105    if (auto* renderer = this->renderer())
     106        renderer->imageResource().setCachedImage(m_imageLoader->image());
    99107}
    100108
  • trunk/Source/WebCore/html/HTMLVideoElement.h

    r217876 r225878  
    9797    bool rendererIsNeeded(const RenderStyle&) final;
    9898    void didAttachRenderers() final;
     99    void updateAfterStyleResolution();
    99100    void parseAttribute(const QualifiedName&, const AtomicString&) final;
    100101    bool isPresentationAttribute(const QualifiedName&) const final;
  • trunk/Source/WebCore/html/ImageInputType.cpp

    r221914 r225878  
    127127}
    128128
    129 void ImageInputType::attach()
    130 {
    131     BaseButtonInputType::attach();
    132 
     129bool ImageInputType::needsPostStyleResolutionCallback()
     130{
     131    return true;
     132}
     133
     134void ImageInputType::updateAfterStyleResolution()
     135{
    133136    HTMLImageLoader& imageLoader = element().ensureImageLoader();
    134137    imageLoader.updateFromElement();
  • trunk/Source/WebCore/html/ImageInputType.h

    r221914 r225878  
    5151    void altAttributeChanged() override;
    5252    void srcAttributeChanged() override;
    53     void attach() override;
     53    bool needsPostStyleResolutionCallback() override;
     54    void updateAfterStyleResolution() override;
    5455    bool shouldRespectAlignAttribute() override;
    5556    bool canBeSuccessfulSubmitButton() override;
  • trunk/Source/WebCore/html/InputType.cpp

    r225680 r225878  
    588588}
    589589
    590 void InputType::attach()
     590bool InputType::needsPostStyleResolutionCallback()
     591{
     592    return false;
     593}
     594
     595void InputType::updateAfterStyleResolution()
    591596{
    592597}
  • trunk/Source/WebCore/html/InputType.h

    r225680 r225878  
    236236    virtual RenderPtr<RenderElement> createInputRenderer(RenderStyle&&);
    237237    virtual void addSearchResult();
    238     virtual void attach();
     238    virtual bool needsPostStyleResolutionCallback();
     239    virtual void updateAfterStyleResolution();
    239240    virtual void detach();
    240241    virtual void minOrMaxAttributeChanged();
  • trunk/Source/WebCore/loader/ImageLoader.cpp

    r225499 r225878  
    3737#include "HTMLObjectElement.h"
    3838#include "HTMLParserIdioms.h"
     39#include "NoEventDispatchAssertion.h"
    3940#include "Page.h"
    4041#include "RenderImage.h"
     
    158159void ImageLoader::updateFromElement()
    159160{
     161    RELEASE_ASSERT(NoEventDispatchAssertion::InMainThread::isEventAllowed());
    160162    // If we're not making renderers for the page, then don't load images. We don't want to slow
    161163    // down the raw HTML parsing case by loading images we don't intend to display.
  • trunk/Source/WebCore/svg/SVGImageElement.cpp

    r224213 r225878  
    190190{
    191191    SVGGraphicsElement::insertedIntoAncestor(insertionType, parentOfInsertedTree);
    192     if (!insertionType.connectedToDocument)
    193         return InsertedIntoAncestorResult::Done;
    194     // Update image loader, as soon as we're living in the tree.
    195     // We can only resolve base URIs properly, after that!
     192    if (insertionType.connectedToDocument)
     193        return InsertedIntoAncestorResult::NeedsPostInsertionCallback;
     194    return InsertedIntoAncestorResult::Done;
     195}
     196
     197void SVGImageElement::didFinishInsertingNode()
     198{
    196199    m_imageLoader.updateFromElement();
    197     return InsertedIntoAncestorResult::Done;
    198200}
    199201
  • trunk/Source/WebCore/svg/SVGImageElement.h

    r223802 r225878  
    5151    void didAttachRenderers() final;
    5252    InsertedIntoAncestorResult insertedIntoAncestor(InsertionType, ContainerNode&) final;
     53    void didFinishInsertingNode() final;
    5354
    5455    RenderPtr<RenderElement> createElementRenderer(RenderStyle&&, const RenderTreePosition&) final;
Note: See TracChangeset for help on using the changeset viewer.