CVE-2025-43343
Overview
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.
Attack Path
- 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.
- 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.
- Misposition scratch slots Pre-patch, OMG reads exception/stack values from the wrong scratch-buffer indices for the IPInt layout.
- Corrupt the value stack The rematerialized stack is misaligned, crashing or type-confusing the compiled code in the WebContent process.
Impact Assessment
Changed Functions
| Function | Change | Notes |
|---|---|---|
OMGIRGenerator::addLoopSource/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::connectValuesAtEntrypointSource/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.jsSource/JavaScriptCore/wasm/WasmOMGIRGenerator.cpp
Audit Directions
- OSR scratch-buffer index parityAudit connectValuesAtEntrypoint/addLoop index accounting against both IPInt and legacy interpreter layouts for all control-frame kinds.
- Tier-dependent slot layoutsgrep for Options::useWasmIPInt() around stack/exception slot positioning to ensure every OSR path branches consistently.
- Catch/try frame handlingReview exception-variable rematerialization in OMG/BBQ OSR for correct per-frame slot advancement.