Medium CVSS 9.8 webkit Type Confusion 🔧 Commit mapped

Overview

Medium
Severity
9.8
CVSS
No
Exploited ITW
Fixed
Fix Status
DescriptionProcessing maliciously crafted web content may lead to an unexpected process crash
ComponentJSC Wasm
Bug ClassType Confusion
Tracker296490
Fix commit899a38cf9a50 (WebKit/WebKit) +130/-3
CWECWE-119 (Buffer bounds error)
CVSS vectorCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
CISA KEVNot listed
Creditedan anonymous researcher
Disclosed2025-09-15

Background

OMG tier / OSR entry
The optimizing wasm JIT; loop OSR entry rebuilds the value stack from an OSR scratch buffer.
OSR scratch buffer
A buffer holding live values at OSR-entry, read back in a fixed index order that must match the source tier’s layout.
IPInt (useWasmIPInt)
The in-place interpreter tier whose stack/exception slot layout differs from the older interpreter’s.
Exception variable / catch frame
An exception value bound in a catch control frame that occupies a scratch-buffer slot at OSR entry.

Root Cause Analysis

JavaScriptCore’s OMG (optimizing) wasm tier rematerializes the value stack at loop OSR entry by reading values from an OSR scratch buffer in a fixed index order (connectValuesAtEntrypoint / addLoop in OMGIRGenerator). Exception-handling control frames contribute an ’exception’ value that occupies a scratch-buffer slot, and the ordering must match how the source tier laid out the buffer. When the in-place interpreter tier (useWasmIPInt) is enabled, the exception values for enclosing try/catch frames are positioned differently, but the pre-patch OMG code did not account for that: it handled the exception variable unconditionally (only advancing indexInBuffer for try frames) rather than following the IPInt layout, so at OSR entry into a loop nested inside catch handlers it read values from the wrong scratch-buffer slots. Consuming a stack slot at the wrong offset (e.g. treating a non-exception slot as the exception, or misaligning all subsequent values) corrupts the rematerialized value stack, crashing (or type-confusing) the OMG-compiled code.

The fix, when Options::useWasmIPInt() is set, walks the parser control stack and, for each catch frame, loads the exception from the scratch buffer into the frame’s exception variable (and advances indexInBuffer for try frames), matching the IPInt slot layout; it also guards the old exceptionVariable handling with !useWasmIPInt().

The restored invariant is that OSR-entry stack-slot positioning for exception values matches the active lower tier’s scratch-buffer layout.

Key insight
OMG loop OSR-entry didn’t match the IPInt tier’s scratch-buffer layout for exception slots, so values were read from the wrong indices and the rematerialized value stack was corrupted; positioning exception loads per the IPInt control stack fixes it.

Attack Path

  1. Craft wasm with loops in catch frames Build a module (with IPInt enabled) whose function has loops nested inside try/catch handlers, forcing OMG loop OSR entry.
  2. Trigger OMG OSR entry Run the function hot so it OSR-enters the OMG tier at the loop with catch frames on the control stack.
  3. Misposition scratch slots Pre-patch, OMG reads exception/stack values from the wrong scratch-buffer indices for the IPInt layout.
  4. Corrupt the value stack The rematerialized stack is misaligned, crashing or type-confusing the compiled code in the WebContent process.

Impact Assessment

An OSR-entry stack-slot mispositioning in the OMG wasm JIT when IPInt is enabled and loops are nested in catch handlers, reachable from crafted wasm in the WebContent process. Misaligned value-stack rematerialization is a corruption/type-confusion-class bug; the observed effect is a crash. Confined to WebContent; rated medium.

Changed Functions

FunctionChangeNotes
OMGIRGenerator::addLoop
Source/JavaScriptCore/wasm/WasmOMGIRGenerator.cpp
modified When useWasmIPInt(), walks the control stack loading each catch frame's exception from the scratch buffer (and advancing indexInBuffer for try), matching the IPInt OSR-entry slot layout.
OMGIRGenerator::connectValuesAtEntrypoint
Source/JavaScriptCore/wasm/WasmOMGIRGenerator.cpp
modified Guards the previous unconditional exceptionVariable handling with !useWasmIPInt() so it doesn't double/mis-position exception slots under IPInt.

Files Changed

  • JSTests/wasm/stress/omg-osr-stack-slot-positioning.js
  • Source/JavaScriptCore/wasm/WasmOMGIRGenerator.cpp

Audit Directions

  • OSR scratch-buffer index parity
    Audit connectValuesAtEntrypoint/addLoop index accounting against both IPInt and legacy interpreter layouts for all control-frame kinds.
  • Tier-dependent slot layouts
    grep for Options::useWasmIPInt() around stack/exception slot positioning to ensure every OSR path branches consistently.
  • Catch/try frame handling
    Review exception-variable rematerialization in OMG/BBQ OSR for correct per-frame slot advancement.

Original Bug Report

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