CVE-2025-24189
Overview
Background
- WASM GC arrays / array.init_data
- WebAssembly garbage-collected arrays; array.init_data copies bytes from a module data segment into an array.
- element vs byte extent
- An array of N elements spans N*elementSize bytes; bounds must be checked in bytes, not element count.
- CheckedUint32
- An overflow-trapping unsigned type used to validate the multiplication size*elementSize.
Root Cause Analysis
This fixes an out-of-bounds read in the WebAssembly GC array.init_data implementation caused by a source-range bounds check performed in element units rather than bytes. arrayInitData copies size elements from a passed data segment (at srcOffset) into a WASM array whose elements are elementSize bytes.
Pre-patch, after checking the destination range, it validated the source only as CheckedUint32 lastSrcElementIndexChecked = srcOffset + size (an element count) for overflow, then performed the copy over size * elementSize bytes (instance->copyDataSegment(…, size * elementSize, …)). Because the overflow/extent check ignored elementSize, the actual byte extent (size * elementSize + srcOffset) could overflow or exceed what was validated, so a large size with a multi-byte element type reads out of bounds from the data segment.
The fix computes the byte extent with overflow checking — CheckedUint32 lastSrcByteChecked = size; lastSrcByteChecked *= elementSize; lastSrcByteChecked += srcOffset; — and returns false if it overflows, before copying.
The restored invariant is that the source byte range (size*elementSize + srcOffset), not just the element count, is overflow-checked. The regression test invokes array.init_data with size = -2 (0xFFFFFFFE).
Attack Path
- Define a WASM GC array + data segment Create a module with a mutable array type and a data segment.
- Call array.init_data with a huge size Invoke array.init_data with a size (e.g. 0xFFFFFFFE) whose byte extent size*elementSize overflows the element-count-only check.
- Read out of bounds The copy reads size*elementSize bytes from the data segment beyond its bounds into the array.
- Disclose / corrupt memory Use the OOB-sourced bytes as an information leak or corruption primitive in the WebContent process.
Impact Assessment
Changed Functions
| Function | Change | Notes |
|---|---|---|
arrayInitDataSource/JavaScriptCore/wasm/WasmOperationsInlines.h |
modified | Computes the source byte extent (size * elementSize + srcOffset) with CheckedUint32 and returns false on overflow, instead of only checking srcOffset + size in element units. |
Audit Directions
- Same file: element vs byte boundsAudit arrayInit/arrayCopy/arrayFill and other WasmOperationsInlines routines for bounds checks in element units that feed byte-sized copies (size * elementSize).
- Overflow in size mathGrep WASM operations for multiplications by elementSize / stride not wrapped in CheckedUint32 before an access.