← All issues

[10] WebAssemblyGCStructure skipped during end-of-GC weak-reference clearing

Severity: Medium | Component: JSC Heap finalisation | d55bf0c

이 항목이 Medium으로 평가된 이유는 다음과 같습니다. diff는 Wasm-GC structure subspace에 대한 full GC 종료 시점의 weak reference 정리 로직을 복원합니다. 살아남은 WebAssemblyGCStructure가 해제된 cell을 가리키는 stale 내부 포인터를 보유할 수 있으며, slot이 재사용된 이후 해당 포인터를 다시 읽으면 Wasm GC type descriptor에 대한 UAF 또는 type confusion이 발생할 수 있습니다.

Structure::finalizeUnconditionally는 GC 종료 단계에서 반드시 호출되어야 합니다. StructureBrandedStructure는 올바르게 처리되고 있지만, WebAssemblyGCStructure는 누락된 상태였습니다.

Source/JavaScriptCore/heap/Heap.cpp

void Heap::finalizeUnconditionalFinalizers()
{
if (collectionScope == CollectionScope::Full) {
finalizeMarkedUnconditionalFinalizers<Structure>(structureSpace, collectionScope);
finalizeMarkedUnconditionalFinalizers<BrandedStructure>(brandedStructureSpace, collectionScope);
+#if ENABLE(WEBASSEMBLY)
+ finalizeMarkedUnconditionalFinalizers<WebAssemblyGCStructure>(webAssemblyGCStructureSpace, collectionScope);
+#endif
}

누락되어 있던 dispatch 호출 지점 하나가 추가되었습니다. CollectionScope::Full 분기 안에서, 기존의 StructureBrandedStructure dispatch와 함께 finalizeMarkedUnconditionalFinalizers<WebAssemblyGCStructure>(webAssemblyGCStructureSpace, collectionScope)가 호출됩니다. 이 호출은 #if ENABLE(WEBASSEMBLY) 조건으로 게이팅됩니다.

병렬 allocator subspace에 대한 weak reference finalization dispatch가 누락되어, full GC 이후 살아남은 Structure 계열 객체 내부에 stale 포인터가 잔존합니다.

JSC는 GC로 관리되는 cell을 타입별 subspace(structureSpace, brandedStructureSpace, webAssemblyGCStructureSpace)로 구성하며, 각 subspace는 collection 시 개별적으로 순회합니다. finalizeUnconditionally는 marking에서 살아남은 cell에 대해 collection 종료 시 호출되는 JSC GC hook으로, 대상이 살아남지 못한 weak reference를 정리하는 역할을 담당합니다. 이 hook이 호출되지 않으면, 살아남은 객체가 방금 해제된 cell을 가리키는 포인터를 그대로 보유할 수 있습니다. Structure는 property layout, prototype, transition link를 기록하는 JSC의 type descriptor로, 이 중 많은 링크가 weak reference로 유지됩니다. WebAssemblyGCStructure는 WebAssembly GC proposal에서 도입된 Wasm GC 타입(RTT 및 supertype chain을 갖는 struct/array)을 지원하는 Structure의 subclass입니다. Full GC(CollectionScope::Full)는 heap 전체를 스캔하므로, Structure 내부의 weak slot은 반드시 이 시점에 정리되어야 합니다.

full GC 종료 단계의 dispatcher는 StructureBrandedStructure 인스턴스에 대해서는 Structure::finalizeUnconditionally를 순회했습니다. 그러나 병렬로 존재하는 WebAssemblyGCStructure subspace에는 동일한 finalizer가 전혀 호출되지 않았습니다. Structure::finalizeUnconditionally는 내부의 weak reference(transition table, 캐시된 prototype/parent reference 등 유사한 weak slot)를 순회하며, marking에서 살아남지 못한 cell을 가리키는 항목을 정리합니다. Wasm GC subspace가 건너뛰어진 결과, 동일한 full collection 중에 해제된 cell을 가리키던 살아남은 WebAssemblyGCStructure 인스턴스 내부의 weak reference가 그대로 방치되었습니다.

🔒

Detailed look at how a missing GC finalization dispatch can leave stale internal references behind, and the conditions under which that becomes more than a bookkeeping bug.

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

🔒

Multiple reusable audit patterns identified for GC-subspace dispatch symmetry and weak-reference cleanup, with concrete starting points in the JSC heap and Wasm GC layers.

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