← All issues

[3] Use-After-Free in BaseDateAndTimeInputType::didChangeValueFromControl

Severity: High | Component: WebCore HTML forms | 869d5c5

이 diff는 해제된 this에 대해 virtual call이 여러 차례 수행되는 renderer-reachable UAF를 수정합니다. 대상은 다형 C++ 객체이며, regression test는 input event listener에서 input.type을 교체하는 20줄짜리 JS PoC입니다.

didChangeValueFromControl()input event를 동기적으로 dispatch합니다. 이때 event handler가 input.type을 재할당하면, 현재의 BaseDateAndTimeInputType 인스턴스가 소멸됩니다. 해당 인스턴스의 유일한 소유자는 HTMLInputElement::m_inputType입니다. handler가 반환된 뒤, 메서드는 이미 해제된 this에 대해 setupDateTimeChooserParameters()showDateTimeChooser() 호출을 계속 수행합니다.

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();
}

BaseDateAndTimeInputTyperef()/deref() override를 통해 ref-countable 구조로 전환되었으며, 두 메서드는 모두 InputType에 위임합니다. DateTimeEditElementEditControlOwner의 기반은 CanMakeWeakPtr에서 AbstractRefCountedAndCanMakeWeakPtr로 변경되었고, DateTimeEditElement 내의 모든 m_editControlOwner 역참조는 로컬 RefPtr로 먼저 promote하는 방식으로 재작성되었습니다. setupDateTimeChooserParameters에서는 ASSERT(element())가 런타임 null check로 교체되었습니다. type swap으로 back-pointer가 초기화된 경우, 호출자가 정상적으로 처리를 중단하게 됩니다.

JavaScript re-entrancy 경계를 넘어 callback 대상을 유지하지 않은 패턴. 대상의 lifetime은 dispatch된 event가 변경할 수 있는 가변 HTML element 상태에 의존합니다.

<input type=date|datetime-local|month|time|week>DateTimeEditElement를 기반으로 구성된 shadow tree를 통해 mm/dd/yyyy 위젯을 렌더링합니다. DateTimeEditElement는 소유자인 DateTimeEditElementEditControlOwner를 가리키는 back-pointer를 보유하며, 실제 구현체는 BaseDateAndTimeInputType입니다. 필드 값이 수정되면 DateTimeEditElement::fieldValueChanged()가 호출됩니다. 이 함수는 didChangeValueFromControl()을 통해 소유자에게 알림을 전달하고, 결과적으로 DOM input event가 발생합니다. HTMLInputElement::m_inputType은 활성 InputType 서브클래스의 유일한 소유자입니다. input.type = 'text'를 할당하면 HTMLInputElement::updateType()m_inputType을 교체하며, 이전 인스턴스는 소멸됩니다. WeakPtr은 lifetime을 연장하지 않고 관찰만 하는 반면, RefPtr은 lifetime을 연장합니다. AbstractRefCountedAndCanMakeWeakPtr은 두 가지를 동시에 지원합니다.

shadow-tree control은 소유자를 bare WeakPtr로만 보유하고 있었습니다. 따라서 JS event handler가 input.type을 재할당하면, BaseDateAndTimeInputType을 살려두는 stack 참조가 존재하지 않게 됩니다. 실행 흐름이 didChangeValueFromControl()로 돌아왔을 때, 이미 해제된 this에 대해 virtual call이 계속 수행되었습니다.

🔒

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.

더 확인하려면 구독해 주세요

🔒

Several reusable audit patterns identified, including a fuzzing harness shape that generalizes this bug class across multiple form control subsystems.

더 확인하려면 구독해 주세요