[3] Use-After-Free in BaseDateAndTimeInputType::didChangeValueFromControl
An input handler that reassigns the field's own type frees the InputType object mid-method, then dispatch continues on the freed this.
Rated High because the diff fixes a renderer-reachable UAF on a polymorphic C++ object with multiple virtual calls performed on
thisafter the free; the regression test is a 20-line JS PoC that swapsinput.typefrom aninputevent listener.
didChangeValueFromControl() dispatches the input event synchronously; an event handler that reassigns input.type destroys the current BaseDateAndTimeInputType instance (the unique owner is HTMLInputElement::m_inputType). When the handler returns, the method continues calling setupDateTimeChooserParameters() and showDateTimeChooser() on this — now freed memory.
Source/WebCore/html/BaseDateAndTimeInputType.cpp
Source/WebCore/html/BaseDateAndTimeInputType.h
Source/WebCore/html/shadow/DateTimeEditElement.cpp
Patch Details
BaseDateAndTimeInputType is made ref-countable via ref()/deref() overrides forwarding to InputType; DateTimeEditElementEditControlOwner migrates from CanMakeWeakPtr to AbstractRefCountedAndCanMakeWeakPtr. Every m_editControlOwner dereference in DateTimeEditElement is rewritten to promote to a local RefPtr first. setupDateTimeChooserParameters swaps an ASSERT(element()) for a runtime null check so callers bail cleanly when the back-pointer has been cleared by a type swap.
Failure to retain a callback target across a JavaScript re-entrancy boundary, where the target's lifetime is owned by mutable HTML element state that the dispatched event can change.
Background
<input type=date|datetime-local|month|time|week> renders its mm/dd/yyyy widget through a shadow tree built on DateTimeEditElement, which holds a back-pointer to its owning DateTimeEditElementEditControlOwner (implemented by BaseDateAndTimeInputType). On field edits, DateTimeEditElement::fieldValueChanged() notifies the owner via didChangeValueFromControl(), which fires the DOM input event. HTMLInputElement::m_inputType is the unique owner of the active InputType subclass; assigning input.type = 'text' causes HTMLInputElement::updateType() to replace m_inputType, destroying the previous instance. WeakPtr observes lifetime without extending it; RefPtr extends it; AbstractRefCountedAndCanMakeWeakPtr allows both simultaneously.
Analysis
The shadow-tree control held its owner via a bare WeakPtr, so when the JS event handler reassigned input.type, no stack reference kept the BaseDateAndTimeInputType alive. Control unwound back into didChangeValueFromControl(), which proceeded with virtual calls on the freed this.
To weaponize, an attacker would race a same-sized allocation into the freed slot during the event handler — another InputType subclass or any similarly-sized scriptable object — then exploit the vtable dispatch on the freed object or one of the member reads in setupDateTimeChooserParameters / showDateTimeChooser. The presence of virtual dispatch on freed this is the classic vtable-based control-flow hijack precursor on successful heap reclaim; absent reclaim, the observable effect is a renderer crash.
This vulnerability weakens memory safety inside the WebContent renderer. The HTML spec implicitly assumes an InputType survives dispatch of the events it triggers; before the fix, that invariant did not hold whenever m_inputType was replaced from inside such a handler.
Audit directions
- Shadow-tree controls calling back into
InputTypeover aWeakPtr.HTMLInputElement::m_inputTypeis oneinput.type = ...away from destruction. Audit everyInputTypesubclass that registers as a callback owner on a shadow element —SearchInputType,ColorInputType,RangeInputType,FileInputTypeand theirdid*FromControlentry points — and verify each callback site either holds aRefPtrto theInputTypeacross the entire body or returns immediately after the re-entrant call. WeakPtr<Owner>dereferenced multiple times across a JS re-entrancy point. The newAbstractRefCountedAndCanMakeWeakPtrbase is the canonical fix shape; grep forCanMakeWeakPtr<in classes that act as callback interfaces and check whether they should beAbstractRefCountedAndCanMakeWeakPtr<>instead.ASSERT(element())inInputTypereachable after a type swap. GrepSource/WebCore/html/and trace whether any reachable caller can run afterupdateType()has nulled the back-pointer.- Regression test as audit oracle. For every input type, register a listener that performs
input.type = <random>/input.remove()/input.replaceWith(...)and exercise typical user-driven flows (focus, key input, picker open). This harness shape has historically found UAFs inHTMLSelectElementandHTMLMediaElement.