[3] Use-After-Free in BaseDateAndTimeInputType::didChangeValueFromControl
Severity: High | Component: WebCore HTML forms | 869d5c5
Rated High because the diff fixes a renderer-reachable UAF on a polymorphic C++ object with multiple virtual calls performed on this after the free; the regression test is a 20-line JS PoC that swaps input.type from an input event 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
bool BaseDateAndTimeInputType::setupDateTimeChooserParameters(DateTimeChooserParameters& parameters)
{
- ASSERT(element());
+ RefPtr element = this->element();
+ if (!element)
+ return false;
- Ref element = *this->element();
Source/WebCore/html/BaseDateAndTimeInputType.h
+ void ref() const final { InputType::ref(); }
+ void deref() const final { InputType::deref(); }
Source/WebCore/html/shadow/DateTimeEditElement.cpp
void DateTimeEditElement::fieldValueChanged()
{
- if (m_editControlOwner)
- m_editControlOwner->didChangeValueFromControl();
+ if (RefPtr editControlOwner = m_editControlOwner)
+ editControlOwner->didChangeValueFromControl();
}
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.
Aa Aaaaaaaaaa Aa Aaaaaaaa Aaaaa Aaaa a Aaaaaaaaaa Aaaaaaaaaa Aaaa Aaa Aaaaa Aaaa Aaaaaa Aaa Aaaaa Aaaaaaa a Aaaaaaa Aaaaaaaaaaa Aaaaaaaa Aa Aaa Aaaaaaaaaaaaaaa Aaaaaaaaaa Aaaaaa a Aaaa Aaaaaaa Aaa Aaaaaa Aaaaaaaa Aa Aaa Aaaaa Aaaaaa Aa Aaa Aa Aaa Aaaaaa Aaaaa Aa Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa a Aaaaaaaaaaaaaaaaaaaaaa Aaa Aaaaaaaa Aa Aaaaaaa Aaaaaaaa Aa Aaaaa Aaaaaa Aa Aaa Aaaaaaa Aaaaaaaaaaaa Aaaaaaaaaaaa Aaaaaa Aaaaaaaaa Aa Aaaaaaaaaa Aaaa Aaaaaaaa Aaaaaa Aaaaaaaa Aaa Aaaaaaaaaa Aaaaaa Aa a Aaaaaaaa Aaaaaa
Aaaa Aaaaaaaaaaaaa Aaaaaaa Aaaaaa Aaaaaa Aaaaaa Aaa Aaaaaaaaaa Aaaaaaaaa Aaa Aaaa Aaaa Aaaaaaaaaa Aaaaaaa Aa Aaaaaaaaaaa Aaaaaaaa Aaaaaaaa Aa Aaa Aaaaaa Aa Aaaaaaaaa Aaaaaa Aaa Aaaa Aaaa Aaaaaaaaa Aaa Aaa Aaaa Aaaaaaaa Aaaaaaaaaaaaa Aaa Aaaaaaaa Aaaa Aaaaaa Aaaa a Aaaaaaaa
🔒Detailed walkthrough of how a DOM event handler can free a C++ object mid-method, and the ownership and lifetime implications of the fix's structural change.
Subscribe to read more
Audit directions
a Aaaaaaaaaaaaa Aaaaaaaa Aaaaaaa Aaaa Aaaa Aaaaaaaaaaa Aaaa a Aaaaaaaaaaaa Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa Aa Aaa Aaaaaaaaaaa a Aaaa Aaaa Aaaa Aaaaaaaaaaaa Aaaaa Aaaaa Aaaaaaaaaaa Aaaaaaaa Aaaa Aaaaaaaaa Aa a Aaaaaaaa Aaaaa Aa a Aaaaaa Aaaaaaa a Aaaaaaaaaaaaaaaaaa Aaaaaaaaaaaaaaaaa Aaaaaaaaaaaaaaaaa Aaaaaaaaaaaaaaa Aaa Aaaaa Aaaaaaaaaaaaaaaaa Aaaaa Aaaaaa a Aaa Aaaaaa Aaaa Aaaaaaaa Aaaa Aaaaaa Aaaaa a Aaaaaaaa Aa Aaa Aaaaaaaaaaa Aaaaaa Aaa Aaaaaa Aaaa Aa Aaaaaaa Aaaaaaaaaaa Aaaaa Aaa Aaaaaaaaaa Aaaaa
a Aaaaaaaaaaaaaaaaaa Aaaaaaaaaaaa Aaaaaaaa Aaaaa Aaaaaa a Aa Aaaaaaaaaaa Aaaaaaaa Aaa Aaa Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa Aaaa Aa Aaa Aaaaaaaaa Aaa Aaaaaa Aaaa Aaa Aaaaaaaaaaaaaaaaa Aa Aaaaaaa Aaaa Aaa Aa Aaaaaaaa Aaaaaaaaaa Aaa Aaaaa Aaaaaaa Aaaa Aaaaaa Aa Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa Aaaaaaaa
a Aaaaaaaaaaaaaaaaaaaaa Aa Aaaaaaaaaaa Aaaaaaaaa Aaaaa a Aaaa Aaaaaaa Aaaa Aaaaaaaaaaaaaaaaaaaaaa Aaa Aaaaa Aaaaaaa Aaa Aaaaaaaaa Aaaaaa Aaa Aaa Aaaaa Aaaaaaaaaaaaaa Aaa Aaaaaa Aaa Aaaaaaaaaaaaa
a Aaaaaaaaaaaa Aaaa Aa Aaaaa Aaaaaaaaa Aaa Aaaaa Aaaaa Aaaaa Aaaaaaaa a Aaaaaaaa Aaaa Aaaaaaaa Aaaaaaaaaaa a Aaaaaaaaa a Aaaaaaaaaaaaaaaa a Aaaaaaaaaaaaaaaaaaaaaaaa Aaa Aaaaaaaa Aaaaaaa Aaaaaaaaaaa Aaaaa Aaaaaaa Aaa Aaaaaa Aaaaaa Aaaaaa Aaaa Aaaaaaa Aaaaa Aaa Aaaaaaaaaaaa Aaaaa Aaaa Aa Aaaaaaaaaaaaaaaaaaa Aaa Aaaaaaaaaaaaaaaaaaa
🔒Several reusable audit patterns identified, including a fuzzing harness shape that generalizes this bug class across multiple form control subsystems.
Subscribe to read more