CVE-2025-43432
Overview
Background
- Wasm FunctionParser
- The JSC component that validates/parses a WebAssembly function body against its declared signature.
- TypeDefinition / FunctionSignature
- The interned description of a wasm type; a function’s signature is a FunctionSignature view of a TypeDefinition.
- Bare reference vs Ref<>
- A C++
const T&member aliases without owning, so it dangles if the referent is freed; Ref<> holds a counted strong reference. - Object lifetime / retention
- Holding a strong reference guarantees the object stays alive for the holder’s lifetime.
Root Cause Analysis
JavaScriptCore’s WebAssembly FunctionParser stored the function’s type as const TypeDefinition& m_signature — a bare C++ reference that does not retain the referenced object. The parser uses m_signature throughout function/constant-expression parsing (m_signature.as<FunctionSignature>() in parse, parseConstantExpression, parseBody, and the TailCall/TailCallIndirect/TailCallRef paths). The invariant that made the bare reference ‘safe’ was that the TypeDefinition outlives the parser, but that does not hold in all cases: the TypeDefinition can be released while the parser is still running (e.g. during recursive/streaming parsing where the owning type registry or module information drops the last other reference), leaving m_signature dangling. Any later dereference is a use-after-free.
The fix changes the member to Ref<const TypeDefinition> m_signature, so the parser holds its own strong reference for its entire lifetime, and updates every use to m_signature->template is/as<FunctionSignature>().
The restored invariant is that the parser owns a reference to the signature TypeDefinition it parses against, so the object cannot be freed underneath it. This is the same ‘retain the wasm TypeDefinition, don’t alias it’ class as the GC type-retention fixes, but here on the parser’s input signature.
Attack Path
- Deliver a crafted module Serve a WebAssembly module whose function signatures reference type definitions arranged so a signature’s other references are dropped during parsing.
- Parse the function body FunctionParser holds m_signature as a bare reference to the function’s TypeDefinition while it parses the body / constant expressions.
- Free the signature During parsing the TypeDefinition is released (last owning reference gone), leaving m_signature dangling.
- Use-after-free A subsequent m_signature.as<FunctionSignature>() (e.g. on a tail-call opcode) dereferences freed memory — crash or memory corruption in WebContent.
Impact Assessment
Changed Functions
| Function | Change | Notes |
|---|---|---|
FunctionParser<Context>::m_signatureSource/JavaScriptCore/wasm/WasmFunctionParser.h |
modified | Type changed from `const TypeDefinition&` to `Ref<const TypeDefinition>` so the parser retains its signature for its whole lifetime. |
FunctionParser<Context>::parse / parseConstantExpression / parseBody / tail-call handlersSource/JavaScriptCore/wasm/WasmFunctionParser.h |
modified | Updated all uses to m_signature->template is/as<FunctionSignature>() to match the Ref member. |
Files Changed
Source/JavaScriptCore/wasm/WasmFunctionParser.h
Audit Directions
- Other bare TypeDefinition referencesgrep JSC wasm/ for
const TypeDefinition&/TypeDefinition*members and long-lived locals that don’t retain via Ref/RefPtr. - Parser-held aliasesAudit FunctionParser and related wasm parsers/validators for other members aliasing module-owned data (ModuleInformation, signatures) across parsing.
- Ref-vs-reference membersLook for
&members initialized from getRef()/registry lookups elsewhere that assume the referent outlives the holder.