[11] AudioContext destructor touches Document during Document's own destruction
Severity: Medium | Component: WebCore Web Audio | ed04ff4
~Document 내부의 BaseAudioContext::deleteMarkedNodes를 통해 도달하는 ~AudioContext가 절반쯤 파괴된 Document에 쓰기를 수행하는 UAF-during-destruction을 수정하는 패치이므로 Medium으로 평가됩니다. 해제된 슬롯 내용에 대한 attacker의 영향력은 간접적입니다. Document storage가 해제된 뒤 그 자리를 차지하는 allocation에 따라 제한됩니다.
Document destructor가 호출되는 시점에, 현재 파괴 중인 Document를 참조하는 code path로 진입할 가능성이 있습니다. 해당 경로는 다음과 같습니다: Document::~Document → ScriptExecutionContext::~ScriptExecutionContext → BaseAudioContext::deleteMarkedNodes → AudioContext::~AudioContext → Document::removeAudioProducer. 패치는 audio producer 제거를 AudioContext::stop()에서 처리하도록 변경하고, ~AudioContext를 !isStopped() 조건으로 보호합니다.
Source/WebCore/Modules/webaudio/AudioContext.cpp
AudioContext::~AudioContext()
{
m_mediaSession->invalidateClient();
- if (RefPtr document = this->document())
- document->removeAudioProducer(*this);
+ if (!isStopped()) {
+ if (RefPtr document = this->document())
+ document->removeAudioProducer(*this);
+ }
}
...
+void AudioContext::stop()
+{
+ if (RefPtr document = this->document())
+ document->removeAudioProducer(*this);
+ BaseAudioContext::stop();
+}
Source/WebCore/Modules/webaudio/AudioContext.h
// ActiveDOMObject
+ void stop() final;
void suspend(ReasonForSuspension) final;
Patch Details
AudioContext teardown을 재구성하는 변경은 세 가지입니다. 먼저 ~AudioContext가 document->removeAudioProducer(*this) 호출을 if (!isStopped()) 조건으로 감쌉니다. 다음으로 새로운 override인 AudioContext::stop()은 BaseAudioContext::stop()에 위임하기 전에 document->removeAudioProducer(*this)를 먼저 호출합니다. 마지막으로 BaseAudioContext::stop()의 접근 제한이 private에서 public으로 상향되어, 파생 클래스에서 직접 이를 호출할 수 있게 됩니다. stop()의 실행 시점은 Document::commonTeardown → ScriptExecutionContext::stopActiveDOMObjects 흐름 내, Document destructor 시작 이전입니다. 수동 ASAN reproducer도 추가되었습니다.
소유 객체 자신의 teardown에 의한 부수 효과로 실행되는 child destructor에서, 절반쯤 파괴된 소유 객체로의 re-entrant 호출.
Background
AudioContext는 BaseAudioContext를 상속하며, BaseAudioContext는 ThreadSafeRefCounted이면서 ActiveDOMObject(per-Document lifecycle interface)를 상속합니다. ActiveDOMObject는 stop() hook을 제공하는데, Document::commonTeardown이 ~Document 실행 이전에 ScriptExecutionContext::stopActiveDOMObjects를 통해 이를 호출합니다. BaseAudioContext::deleteMarkedNodes는 삭제 예정으로 표시된 audio node의 reference를 해제하는 deferred-deletion sweep입니다. 해당 reference가 마지막 참조였을 경우, 소유 AudioContext의 소멸이 deleteMarkedNodes 내부에서 연쇄적으로 발생합니다. Document::addAudioProducer/removeAudioProducer는 Document 위에서 MediaProducer* 집합을 관리하며, 현재 audio를 생성 중인 context를 추적합니다. BaseAudioContext::isStopped()가 true를 반환하는 시점은 stop()이 m_isStopScheduled를 설정한 이후입니다.
Analysis
commit message에 기록된 crash chain의 흐름은 다음과 같습니다. Document::~Document가 실행되면 ~ScriptExecutionContext가 연쇄적으로 실행됩니다. 이 base destructor로 인해 BaseAudioContext::deleteMarkedNodes가 삭제 지연된 AudioContext의 마지막 reference를 해제합니다. 그 결과 ~AudioContext가 호출되고, 내부에서 document->removeAudioProducer(*this)가 실행됩니다. 이 시점에 Document subobject는 파괴 진행 중인 상태입니다. Document에 속하지만 ScriptExecutionContext에는 아직 속하지 않은 필드들이 이미 선언 역순으로 파괴된 뒤입니다. removeAudioProducer는 이 절반쯤 파괴된 Document 객체의 상태를 변경합니다.
Aaa Aaaaaaaaaaaaaaaaaaaaa Aaa Aaaaaaaaaa Aaaaaaa a Aaa Aaaaa Aaaaaaaaaaaaaaaaaaaaaaaaaaa Aaaaaaaaaaaaaaaaaaaaaaa Aa Aaaaaaaaa Aaaa Aaa Aaaaaaaaaa Aaaaaaaa Aaaa Aaaaaaaa Aaaaaaaaaaaaaaaa Aaaaaaaaaaaaaa Aaaaaa Aaaaaaaa Aa Aa Aaaaaaaaaaa Aaaa Aaa Aaa Aaa Aaaaaaaa
a Aaaa Aaaaaaaaa Aaaaaa Aaaaaaa Aaaaaaa Aa Aa Aaa Aaaaaaaaaaaaaaaaaaa Aaaaaaaaaa Aaa Aaa Aa Aa Aaaaaaaaaaa Aaaaa a Aaaa Aaaaaaaaaa Aaaaaa Aa Aa Aaa Aa Aaa Aaaa Aaaaaaaa Aaa Aaaaaaaaaa Aaa Aaa Aaa Aaaaaaaaaaa Aaa Aaaa Aaaaaa Aaaaaa Aaa a Aaaaa Aaaaaaaa Aaaa Aaaaaaaaaa Aaaaaa Aaaaaaaaaa Aaaa Aaaaaaaa Aaaa Aaaa Aaa Aaaaa Aaaaaaaaaa Aa Aaaa Aa Aa Aaa Aaaaaaaaaaaa Aaa Aaaaaa Aaaaaaaa Aaaa Aaaa Aaaaa a Aaa Aaaaaaaaa Aaaaa Aaaaaa Aaaaaaaaaaaaaaaaa Aaaaaa Aaaa Aa Aaaaaaaaaaaaaaaaaa Aaaaaaaaa Aa Aa Aaaaaaaaaaa Aaaaaaaaaa Aaaaaaa Aaaa Aaaaaaaaaaa Aaa Aaaa Aaaaa Aa Aaa Aa Aaa Aaaaaa Aa Aaa Aaaa Aaaaaaaa Aa Aaaaaaaaaa Aaaaa Aaaaaaaaaaa Aa Aa Aa Aaaa Aaaaa Aaaaaaaaaaaaaa Aaa Aaaaaa Aaaa Aaaa
🔒The teardown ordering and re-entrant destructor chain behind this UAF are traced end-to-end, with an assessment of how much attacker control is realistic during the destruction window.
더 확인하려면 구독해 주세요
Audit directions
a Aaaa Aaaaaaaaaa Aa Aaaaaaaaaaaaaaaaaaaaaaaaa Aaaa Aaaaaaaaaaaaaaaaa Aaaaaaaaaaaaa a Aaaaaaaaaaa Aaaa Aaa Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa Aaaaaaaaaaaaaaaaa Aaaaa Aaaa Aa Aaaaaaaaaaa Aaaa Aaa a Aaaaa a Aaaa Aaaaaaaaaa Aaa Aa Aaa Aaaaaa Aaaaaaaaaaa Aaaaaaaaaaaaaaaaaa Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa Aaaaaaaaaaaaaaaaaaaaaaaaaa Aaaa Aaaaaaaaaaaaaaaaa Aa Aaaa Aaaaaaaaaaa Aaaaa Aaaaa Aa Aaaaaaaaaaaaaaaaaaa Aaaaaaaaaaaaaa Aaaaaaaaaaaaaaaaaaaa Aaaaaaaaaaaaaa Aaaaaaaaaaaa Aaaaaaa Aaaaa Aaaaa
a Aaaaaaaa Aaaaaaaaaa Aaaa Aa Aaaaaaaaaa Aaaa Aaaaaaaaaaaaaaaaa Aaaaaaaa Aaaaaaaaaaaaaaaaaaa Aaaaaaaaaaaaaa Aaaaaaaaaaaaaa Aaa Aaa Aa Aaaa Aa Aaaaaaa Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa Aaa Aaaa Aaaa Aaaaa Aaa Aaaaaaaaaa Aaa Aa Aaa Aaaa Aaaa Aaa Aaaaaa Aaaa Aaaaaaaaaaa Aa Aaaaaaaaaaaaaaaaaaaaaaaaaaa Aaaaa Aaaaa Aaaaa
a Aaaaaaaaaa Aaa Aaa Aa Aa Aa Aaa Aaaa Aaaaaaaaaaaaaaaaaa Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa Aaaaa a Aa Aaa Aaaaaaaaaaa Aaa Aaaa Aa Aa Aaa Aaa Aaaaa Aaaaa
a Aaaa Aa Aaa Aa Aaaaaaaaaaaa Aaa Aa Aaa Aa Aaa Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa Aaaaaaaa a Aaa Aaa Aaa Aa Aaaaaaaaaaaaaaaaaaaaaaaaaaa a Aa Aaaaaaaaaaaaaaaaaa Aa Aaaaaa Aaa Aaaaaa a Aaaaaaaaaaaaaaa Aaa Aaaaaa Aaa Aaa Aaaaaa Aaa Aaaaa Aaaaa
🔒Four reusable audit patterns identified around ActiveDOMObject lifetimes and deferred-deletion queues, with concrete subsystem starting points for variant discovery.
더 확인하려면 구독해 주세요