[12] Wasm InstanceAnchor unregistered too late in destructor
Severity: High | Component: JSC Wasm runtime | 76b3468
High로 평가된 이유는 destructor 내 publish/unpublish 순서 역전이 수정되었기 때문입니다. 수정 이전에는 per-instance 상태를 먼저 해제한 뒤, compiler thread가 instance를 찾는 데 사용하는 thread-safe handle을 나중에 해제하는 구조였습니다. 그 사이 넓은 race window가 존재해, compiler thread의 profile merge가 이미 해제된 baselineData slot을 읽을 가능성이 있었습니다.
~JSWebAssemblyInstance는 m_anchor->tearDown()을 호출하기 전에, unregisterMirror, clearJSCallICs, 그리고 importFunctionInfos, tables, baselineDatas에 대한 std::destroy_at 루프를 먼저 실행했습니다. 그러나 compiler thread가 live instance를 찾는 데 사용하는 것이 바로 이 anchor입니다.
Source/JavaScriptCore/wasm/js/JSWebAssemblyInstance.cpp
JSWebAssemblyInstance::~JSWebAssemblyInstance()
{
+ if (m_anchor) {
+ m_anchor->tearDown();
+ m_anchor = nullptr;
+ }
+
m_vm->traps().unregisterMirror(m_stackMirror);
clearJSCallICs(*m_vm);
for (auto& slot : importFunctionInfos())
std::destroy_at(&slot);
for (auto& slot : baselineDatas())
std::destroy_at(&slot);
- if (m_anchor) {
- m_anchor->tearDown();
- m_anchor = nullptr;
- }
}
Patch Details
m_anchor->tearDown()이 destructor의 가장 첫 번째 동작으로 이동했습니다. owned state가 해제되기 전에 먼저 호출됩니다.
Destructor 내 publish/unpublish 순서 역전 패턴. 객체의 owned state가 먼저 해제된 뒤에야 thread-safe handle이 해제되는 구조로, 다른 thread가 부분적으로 해제된 객체를 회수해 역참조할 수 있는 race window가 발생합니다.
Background
JSWebAssemblyInstance는 per-instance Wasm 상태(import call link info, table, per-function baseline profile data)를 소유합니다. Wasm::InstanceAnchor는 thread-safe-refcounted weak handle로, concurrent compiler thread가 Wasm::Module로부터 live instance를 찾는 데 사용됩니다. instance pointer는 m_lock 하에 저장됩니다. Wasm::Module::m_anchors는 ThreadSafeWeakHashSet<InstanceAnchor> 타입입니다. compiler thread는 tier-up 전에 baseline profile을 통합하기 위해 createMergedProfile에서 이 컬렉션을 순회합니다.
Analysis
finishCreation에서는 instance를 m_anchors에 명시적으로 등록합니다. 코드 주석에도 "Expose it to the concurrent compiler"라고 명시되어 있습니다. 이에 대응하는 등록 해제는 destructor의 첫 번째 동작이어야 하지만, 실제로는 마지막에 위치했습니다.
Aaaaaaa Aaaaa Aaaaaaaaaa Aaaaa Aa Aaaaaa Aa Aaaaaaa Aa a Aaaaaaaa Aaa Aaaaaaaaaaaa Aaa a Aaa Aaaaaaaaaaa Aaaa Aaaa Aaaaaa Aa Aaaaaa Aa Aaaaaaaaaaaa Aaaaaaaa Aaaaaaaaa Aaa Aaaaaa Aa Aaa Aaaaaaa Aaaaaaaa Aaaaa Aaaaaaa Aaaaaa Aaaaa Aaa Aaa Aa Aaa Aaaaaa Aaaaa Aaaaaaaaa Aaaaaaaaaaa Aaaaaaaaaaaaaaaaaa Aa Aaaaaaaaaaaaaaaaaa Aa Aaaaaa Aa Aa Aa Aa Aaaa Aaaaaaaaaaaaaa Aaaa Aa Aaaaaa a Aaaaaaaa Aaaaaaaaaaaaaaaaaaaaaaaaaaaaa a Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa Aaaaaa a Aaa Aaaaaaaa Aaaaaaa Aa Aaa Aaaaaaaaaaaaaaaaaaaaaa Aaaaa Aaaaa a Aa Aaaaaaaaaa Aaaaaaaaaaaaaaaaaaaaa Aaaaaaa Aaaaaaaa Aaaa Aaaa
a Aaaaaaaaaaaaaa Aaaaaaaaaaaaaaaaaaaaaaa Aaa Aaa Aaaa Aaaaaaa Aa Aaaaaaaa Aaaaaaaa Aa Aaaaaa Aaaaaaaaaa Aaaaaa Aaaa Aaaaaaaaaaa Aaaaaaa a Aaaaa Aaa a Aaaaa Aaaaaaaa Aaaa Aaaaaaaaaa Aaaaaaa Aa Aaaaaaaaaaaa Aaaa Aaaaaaaa Aaaaa Aa Aaa Aaaaaaaaaa Aa a Aaaaa
🔒Explores the publish/unpublish symmetry that was inverted here, and what an attacker would need to win the destructor race from web content.
더 확인하려면 구독해 주세요
Audit directions
a Aaaaaaaaaaaaa Aa Aaaaaaa Aaaaaaaaa Aa Aaaaaaaaaaa Aaaa Aaaaaaaaaaaaa Aaaa Aaaaaaaaa Aaaaaaaaaaaaaaaaaaaaaaaaaaaa a Aaaaaaaaaaaaaaaaaaa Aa Aa Aa Aaa Aaaaaa Aaa Aa Aaaaaaaaaaa a Aa Aaa Aaaaaaa Aaaa Aaa Aaaa Aa Aaaaaaa Aaaaa Aaaaaa
a Aaaaaaaaaaaaaaaaaaa Aaaaaaaaaaa Aaaaa Aaaaaaaaaaaaaaaa Aaa Aaaaaaaa Aa Aaaaaaaaaa Aaa Aaa Aaa Aaaaa Aaaa Aaaaaaaaaaa Aaaaaa Aaaaaaaaaaaaaaaaaaaaaa Aaaaaaaaaaaaaaaaaaaa Aaaaaaaaaaaaaaaaaaaaa Aaaaaaaaaaaaaaaaaaaaaa Aaaaaa
a Aaaaaaaaaaaaaaaaa Aaaaaaa Aaaaaaa Aaaaa Aaaaaaa Aaaa Aaaaaaaaaa Aaaaaaaaaaaa Aaaa Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa Aa Aaa Aaaaaa Aaaa Aaaa Aaa Aaaaaaaaaaa Aa Aa Aa Aa Aaaaaaa Aa Aaaaaaaaaaaa Aaa Aaa Aaaaaa
a Aaaaaaa Aaaaaaaaaaa Aaaaaaaaa Aa Aaaaaaaaaaaaaaaaaaaaaaaaaa Aaaaaaaaaaaaaaaa Aaaaaaaaaaaaaaa Aaaaaa Aa Aa Aa Aa Aaaaaaaaa Aaaaaa
🔒Several reusable audit patterns identified for destructor/registry ordering bugs across JSC's concurrent subsystems, with concrete starting points for variant discovery.
더 확인하려면 구독해 주세요