← All issues

[JSC] Fix wasm type parsing regression by making RTT formal canonicalized types

94e35cf parent — see above; this is 103a40a

// JSTests/wasm/stress/cross-module-rtt-identity.js
// Two separately compiled modules declare the same recursive struct type.
// Isorecursive canonicalization must map both to the same RTT pointer
// so that a ref.cast in module B on a value produced by module A succeeds.

const { makeLeaf, leafVal } = new WebAssembly.Instance(new WebAssembly.Module(M_A)).exports;
const { castAndRead }       = new WebAssembly.Instance(new WebAssembly.Module(M_B)).exports;

const b = castAndRead(leaf);
if (b !== v)
    throw new Error(`B castAndRead(${v}): expected ${v}, got ${b}`);

WebAssembly GC는 heap에 할당되는 struct, 배열, 재귀 타입을 wasm에 추가합니다. RTT(Runtime Type)는 타입 동일성을 담당하는 객체로, ref.cast와 subtype check 실행 시 포인터 동등성 비교에 사용됩니다. 이때 올바른 동작을 위해서는 isorecursive canonicalization이 필요합니다. 구조적으로 동일한 재귀 타입을 선언하는 두 모듈이 독립적으로 컴파일되더라도 동일한 canonical RTT 포인터를 받아야 하며, 이를 통해 spec이 요구하는 cross-module ref.cast가 정상적으로 성공할 수 있습니다.

이 commit은 JSC의 WebAssembly GC 타입 시스템에서 TypeDefinition을 완전히 제거하고, 모든 런타임 타입 표현을 RTT 중심으로 통합하였습니다. 먼저 type-section 파싱 중에만 존재하는 임시 파싱 구조체(Subtype, RecursionGroup, Projection)를 관리하기 위해 TypeSectionState가 도입되었습니다. 파싱이 완료되면 이 구조체들은 프로세스 전역 TypeInformation 싱글턴에 등록된 canonical RTT로 변환됩니다. 한편 RTT는 이제 sibling RTT에 대한 RefPtr 참조를 보유하며, 상호 재귀 타입에 대해 의도적으로 refcount cycle을 형성합니다. 이 cycle은 V8의 현재 방식과 동일하게 영구적으로 leak되며, 향후 cycle collector가 도입될 때까지 이 방식을 유지합니다. 또한 cross-module isorecursive RTT canonicalization 문제와 GC 구조체 구성 중 반복 순회로 인한 성능 저하(312331@main에서 도입된 regression)도 함께 수정되었습니다.

Wasm GC 타입 인프라를 전면 재작성한 변경으로, TypeSectionState의 임시 객체에서 포인터가 하나라도 외부로 누출되면 모든 cross-module ref.cast 경로에서 도달 가능한 use-after-free가 발생합니다.

🔒

이 취약점 패턴의 변종을 찾기 위한 구체적인 탐색 방향이 포함되어 있습니다

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