CVE-2025-43434
Overview
Background
- Wasm reference type / TypeIndex
- A reference-typed value carries a TypeIndex into the interned TypeDefinition registry describing its type.
- TypeDefinition lifetime
- TypeDefinitions are ref-counted and freed when nothing retains them; a bare TypeIndex does not keep one alive.
- WasmTable / WasmGlobal
- Long-lived wasm objects that can outlive the module which defined their element/value type.
- getRef
- The new accessor that returns a strong reference to a TypeIndex’s definition, or nullptr for primitives/invalid indices.
Root Cause Analysis
JavaScriptCore’s WebAssembly Table and Global store their element/value type as a Wasm::Type that, for reference types, carries a TypeIndex into the interned TypeInformation registry.
Pre-patch, WasmTable and WasmGlobal held that Wasm::Type (m_wasmType / m_type) WITHOUT retaining the underlying TypeDefinition. When the module that defined the type went away, the TypeDefinition the TypeIndex refers to could be freed while the Table/Global lived on, leaving m_type’s TypeIndex dangling; a later type-directed operation on the table/global dereferences the freed TypeDefinition — a use-after-free.
The fix retains the definition: WasmTable gains RefPtr<const TypeDefinition> m_wasmTypeDefinition and WasmGlobal gains RefPtr<const Wasm::TypeDefinition> m_typeDefinition, both initialized with a new TypeInformation::getRef(type.index) that returns the interned TypeDefinition (or nullptr when the index is a primitive type or invalid). Holding that RefPtr keeps the definition alive for the object’s lifetime, so the TypeIndex cannot dangle.
The restored invariant is that a Table/Global naming a reference type retains that type’s definition. (Note: this fix retains the directly-named definition; a later follow-up extended retention to the whole transitive type closure after finding nested types could still dangle.)
Attack Path
- Create a typed table/global Build a wasm module with a table or global whose element/value type is a reference to a module-defined type (carrying a TypeIndex).
- Outlive the module Keep the exported table/global reachable while dropping references to the defining module so its TypeDefinitions can be freed.
- Free the definition Garbage collection reclaims the TypeDefinition the table/global’s Wasm::Type still indexes.
- Use-after-free A type-directed access to the table/global dereferences the dangling TypeIndex, corrupting memory in WebContent.
Impact Assessment
Changed Functions
| Function | Change | Notes |
|---|---|---|
Table::Table / m_wasmTypeDefinitionSource/JavaScriptCore/wasm/WasmTable.cpp |
modified | Retains the table element type's TypeDefinition via RefPtr m_wasmTypeDefinition = TypeInformation::getRef(wasmType.index). |
Global::Global / m_typeDefinitionSource/JavaScriptCore/wasm/WasmGlobal.h |
modified | Retains the global value type's TypeDefinition via RefPtr m_typeDefinition for both constructors. |
TypeInformation::getRefSource/JavaScriptCore/wasm/WasmTypeDefinitionInlines.h |
added | Returns a RefPtr<const TypeDefinition> for a TypeIndex (nullptr for primitive/invalid indices), used to retain reference-type definitions. |
Files Changed
Source/JavaScriptCore/wasm/WasmGlobal.hSource/JavaScriptCore/wasm/WasmTable.cppSource/JavaScriptCore/wasm/WasmTable.hSource/JavaScriptCore/wasm/WasmTypeDefinition.hSource/JavaScriptCore/wasm/WasmTypeDefinitionInlines.h
Audit Directions
- Other bare TypeIndex holdersgrep wasm/ for Wasm::Type/TypeIndex members not paired with a retained TypeDefinition (tags, exceptions, caches).
- Transitive retentionConfirm follow-up work retains the full transitive type closure, since a directly-retained definition can still reference unretained nested types.
- getRef adoptionEnsure every place that stores a reference-typed Wasm::Type long-term uses getRef to retain it.