Medium CVSS 8.8 webkit OOB 🔧 Commit mapped

Overview

Medium
Severity
8.8
CVSS
No
Exploited ITW
Fixed
Fix Status
DescriptionProcessing maliciously crafted web content may lead to memory corruption
ComponentJSC Wasm
Bug ClassOOB
Tracker284332
Fix commit9cee5daeabd1 (WebKit/WebKit)
CWECWE-119 (Buffer bounds error)
CVSS vectorCVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H
CISA KEVNot listed
Creditedan anonymous researcher
Disclosed2025-01-27

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).

Key insight
The source bound for array.init_data was checked in element units while the copy ran in bytes, so size*elementSize could exceed the validated range; checking the byte extent with overflow detection closes the OOB.

Attack Path

  1. Define a WASM GC array + data segment Create a module with a mutable array type and a data segment.
  2. 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.
  3. Read out of bounds The copy reads size*elementSize bytes from the data segment beyond its bounds into the array.
  4. Disclose / corrupt memory Use the OOB-sourced bytes as an information leak or corruption primitive in the WebContent process.

Impact Assessment

An out-of-bounds read from a WASM data segment in the WebContent process, reachable from any page running WebAssembly. It yields a memory-disclosure primitive (and potential corruption depending on downstream use); the advisory rates it memory corruption. The controllable size makes it a reliable leak building block.

Changed Functions

FunctionChangeNotes
arrayInitData
Source/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 bounds
    Audit arrayInit/arrayCopy/arrayFill and other WasmOperationsInlines routines for bounds checks in element units that feed byte-sized copies (size * elementSize).
  • Overflow in size math
    Grep WASM operations for multiplications by elementSize / stride not wrapped in CheckedUint32 before an access.

Original Bug Report

The reporter's bug is still restricted on the tracker.