[8] Wasm GC Type Dependency Tracking: Missing Subtype Expansion
Severity: Medium | Component: JSC WebAssembly GC | a0d2715
Rated Medium because the observable effect is missed GC roots for type definitions reachable through Subtype indirection — a logic error that could lead to premature collection and use-after-free of type metadata — but triggering the actual premature collection requires specific GC timing and nested Subtype hierarchies, and the fix is a single-line canonicalization that may have been caught by sanitizers before a reliable exploit was constructed.
Patch Details
Adds a .expand() call in WebAssemblyGCStructureTypeDependencies::process(Wasm::FieldType, WorkList&) so that when a field's type is a Subtype, the expanded (effective) type definition is added to the work list instead of the unexpanded one.
Source/JavaScriptCore/wasm/js/WebAssemblyGCStructure.cpp
void WebAssemblyGCStructureTypeDependencies::process(Wasm::FieldType fieldType, WorkList& work)
{
if (fieldType.type.is<Wasm::Type>()) {
Wasm::Type type = fieldType.type.as<Wasm::Type>();
if (isRefWithTypeIndex(type)) {
- SUPPRESS_UNCHECKED_LOCAL const auto& typeDef = Wasm::TypeInformation::get(type.index);
+ SUPPRESS_UNCHECKED_LOCAL const auto& typeDef = Wasm::TypeInformation::get(type.index).expand();
work.append(typeDef);
}
}
}
Failure to canonicalize Wasm GC subtype references before dependency traversal, causing the type graph walk to miss transitive dependencies reachable only through expanded types.
Background
WebAssembly GC (the gc proposal) introduces struct and array types managed by the JavaScript GC. Types can form subtype hierarchies using the sub keyword — a Subtype wraps a parent type with additional constraints. Internally, WebKit distinguishes between "unexpanded" type definitions (which may be Subtype wrappers) and "expanded" type definitions (the canonical structural form with actual fields). The .expand() method resolves this indirection. WebAssemblyGCStructureTypeDependencies performs a graph traversal of all types reachable from a GC structure's type definition, recording them so the GC knows which type definitions must be kept alive while the structure is live.
Analysis
Before the fix, the process method retrieved the type definition for a field's type index without calling .expand(). For Subtype fields, the unexpanded type definition is merely a wrapper/alias — the actual structural type with its fields is in the expanded form. By appending the unexpanded form to the work list, the traversal found a type with no fields to recurse into (if unexpanded Subtype definitions lack structural fields, as the fix pattern suggests), and the real expanded type — along with all its transitive dependencies — was never scanned.
The inconsistency is notable: the constructor already called .expand() on the initial type, but the field-level recursion did not. This is a classic pattern where a canonicalization step is applied at one entry point but missed at a recursive call site.
Aa a Aaaa Aaaaaaaaaa Aa Aaaaaaaaa Aaaaa Aaaaa Aa Aaaa Aaaaaaaaaa Aaaaa Aaaaaaaa Aa Aaaa Aa Aaaaaaaaaaaaaa Aaaaa Aaaaaaa Aa Aaaaa Aa Aaaaaa Aaaa Aaaaaaaaa Aaaaaaaaaaa Aaaaaaaaaa Aaa Aaaa Aaaaaaaa Aaaaaaaaaa Aa Aaaaaaaa Aaa Aaaaaa a Aaaa Aaaaaa Aaaa Aaaaaa Aaaaaaa Aaaaaaaaaaa Aaaaa Aaaaaaa Aaaaaaaaaa Aa Aaaaaaaaaa Aaaa Aaaaaaaaaaa a Aaaaaa Aaa Aaaaaaaaa Aaaaaaaaaaaaaa Aaaaaaa Aa Aa Aaaaaa Aaa Aaaaaaa Aaaaa Aaaaaaaaaa Aaaa Aaaaaaaaaaaaa Aaaaaa Aaaaaa
Aaaa Aaaaaaaaaaaaa Aaaaaaa Aaaaaa Aaaaaa Aa Aaa Aaaa Aa Aaaa Aaaaaaa Aaa Aa Aaaaaaaaaa Aaaaaaa Aa Aaa Aaaaaaaaa Aaaa Aaaaa Aaaa Aaaaaaaaaaa Aaaaa Aaaa Aaaaaaaaaa Aa Aaaa Aaaaaaaa Aa Aaaaaaaa Aaa Aaaaaa a Aaaa Aaaaaa Aaaa Aaaaaa Aaaaaaa Aaaaaaaaaaa Aaaaa Aaaa a Aaaaaaaaa Aaaaaaa Aaa Aaaa Aa Aaaaaaa Aa Aaa Aaaaaaaaaa Aaaaaaaa
Aaaaaaaaa Aaaaaaa Aaaaaaaaa Aaaaaaaaaa Aa Aaaa Aaaaaaaaaaa Aa Aaaaaaaa Aaaaaaaaa Aa Aaaaaaaa Aaaaaaa Aa Aa Aaaaaa Aaa Aaaaaaa Aaaaa Aaaaaaaaaa Aaaa Aaaaaa Aaaaa Aaaaaaaaaaaaaa Aaa Aaaa Aaaaaaaaa Aaa Aa Aaaaaaaaaaaa Aaaaaaaaa Aa Aaa Aaaaaaaa Aaaa
🔒The ownership and lifetime implications of this GC dependency tracking gap are explored in depth
Subscribe to read more
Audit directions
a Aaaaaaaaaaaaaaaaaa Aaaaa Aaaaaaa Aaaaaaaaaaaaaa Aaaaaa Aaaaa Aaaaaa Aa a Aaaaaaaaa Aaaaaaaaaaaa Aaaaa Aaa Aaaa Aaaaa Aa Aaaaa Aaaa Aaaa Aaaaaa Aaaa Aaaaaaaa Aaaa Aaaaaa a Aaaaaa Aaaa Aaaaa Aaaa Aa Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa Aaaa Aaaaa Aaaa a Aaaaaaaaa Aa Aaaaaaaaaa Aaaa Aaaaa Aaaaaaaaaaaa Aaaaa Aaaa Aaaa Aaa Aaaaaaaaaaaaaaaaaaaaaa Aa Aaaaaaaaaaaaaaaaaaaaaaaaaaaaa Aaa Aaaaa Aaaaaaa Aaa Aaaaaa Aa Aaaaaaaa Aaaaaa Aaaa
a Aaaa Aaaaaaaaaa Aaaaaaaa Aaaaaaaaaaaaaaa Aaaaa Aaaaaaa Aaaaa Aaaa Aa Aaaa Aaaaaaaaaaaaa Aaaaaaaaa Aaaaa Aaaaaaaaaaa Aaaaaa Aaaaaa Aaaaaaaaa Aaaaaa Aaaa Aaaaaaaa Aaa Aaaaa Aaaaaaaaa Aa Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa Aaaaa Aa Aaaaaaaaaaaaaaaaaaaaaa Aaaaaaa Aaa Aaa Aaaaaaaa Aaaaaa Aaaaaaaaaa Aaaaaaaaaaaaa
a Aaaaaa Aaaaaaaa Aa Aaaaaaaaaa Aaaaaaaaaa Aaaaaaaaa Aaaa Aaaaaa Aaaaaaa Aaaa Aaaaaaaaaaa Aaa Aaaaaaaa Aa Aaaa Aaaaaaaaaaa Aaaa Aa Aaa Aa Aaaaaaaaaa Aaaaaaa Aaaaaaaaa Aaaaaa Aaa Aaaaaa Aaaaaaaaaa Aaaaa Aaaaa Aaaaaaaaaaa Aaaaaaa Aaaaa Aaaaaaa Aaaa Aaa Aaaaaaaaaa Aaaaaaaa Aaaaaa Aa Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
🔒Multiple reusable audit patterns identified, with concrete starting points for variant discovery across the Wasm GC type system
Subscribe to read more