Medium CVSS 4.3 webkit Type Confusion 🔧 Commit mapped

Overview

Medium
Severity
4.3
CVSS
No
Exploited ITW
Fixed
Fix Status
DescriptionProcessing maliciously crafted web content may lead to an unexpected Safari crash
ComponentJSC B3
Bug ClassType Confusion
Tracker316791
Fix commit9f07374e9eb2 (WebKit/WebKit) +174/-2
CWECWE-119, CWE-787 (Buffer bounds error, Out-of-bounds write)
CVSS vectorCVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:L
CISA KEVNot listed
CreditedOpenAI Codex Security - Amy Burnett
Disclosed2026-08-17

Background

Select specialization (ReduceStrength)
A B3 transform that clones the values between a Select and a Check to specialize each Select arm.
Cloning-forbidden value kind
A B3 value whose identity must be unique (e.g. a call patchpoint tied to an exception stackmap); cloning it aliases semantics.
Catch-restoration stackmap / CallSiteIndex
Per-call-site exception state used to restore registers/stack when unwinding to a catch; aliasing it across call sites corrupts restoration.

Root Cause Analysis

This fixes a B3 miscompilation where strength reduction’s Select specialization cloned values that must not be cloned — specifically call patchpoints inside a try/catch that carry an exception-restoration stackmap. In B3ReduceStrength, when a Select feeds a Check, specializeSelect splits the path and CLONES the values between the Select and the Check to specialize each arm.

Pre-patch, it did this whenever a suitable Select was found, without verifying the intervening values are cloneable. Separately, WASM call patchpoints generated inside a try (OMGIRGenerator::createCallPatchpoint with m_tryCatchDepth) carry a catch-restoration stackmap keyed by CallSiteIndex (used by preparePatchpointForExceptions to restore state when an exception unwinds to the catch). Cloning such a patchpoint would create two call sites aliasing ONE stackmap/CallSiteIndex, so on exception the wrong state is restored — a type-confusion/memory-corruption condition.

The fix marks those in-try call patchpoints as cloningForbidden (auto patchpointKind = m_tryCatchDepth ? cloningForbidden(Patchpoint) : Patchpoint, with an ASSERT in preparePatchpointForExceptions that the patch kind is cloningForbidden), and makes specializeSelect check that ALL values between the Select and the Check are cloneable (kind().isCloningForbidden()) before specializing — bailing if any forbids cloning.

The restored invariant is that B3 never clones a value whose identity is semantically required (like an exception-stackmap-bearing call), so exception restoration cannot be aliased across call sites.

Key insight
Select specialization cloned values without checking cloneability, and in-try call patchpoints (which carry a per-call-site exception stackmap) were cloneable, so cloning them aliased two call sites to one stackmap; forbidding cloning of those patchpoints and gating specialization on isCloningForbidden fixes it.

Attack Path

  1. Compile WASM with try/catch calls Run a WASM module with calls inside a try block so OMG generates call patchpoints carrying catch-restoration stackmaps.
  2. Feed a Select to a Check Shape the IR so B3 strength reduction attempts Select specialization over a region containing such a call patchpoint.
  3. Clone the uncloneable Pre-patch, specializeSelect clones the in-try call patchpoint, creating two call sites aliasing one exception stackmap/CallSiteIndex.
  4. Corrupt exception restoration On an exception unwinding to the catch, the aliased stackmap restores wrong state — a type-confusion/memory-corruption in the WebContent process.

Impact Assessment

A B3 JIT miscompilation in the WebContent process, reachable from crafted WASM using try/catch around calls. Cloning an exception-stackmap-bearing call patchpoint aliases two call sites to one restoration record, corrupting state on exception — a memory-corruption primitive the advisory rates as a crash.

Changed Functions

FunctionChangeNotes
ReduceStrength Select specialization (specializeSelect gate)
Source/JavaScriptCore/b3/B3ReduceStrength.cpp
modified Before specializing, walks the values from m_index back to the Select and bails if any value->kind().isCloningForbidden(), so uncloneable values (e.g. in-try call patchpoints) are never cloned.
OMGIRGenerator::createCallPatchpoint / preparePatchpointForExceptions
Source/JavaScriptCore/wasm/WasmOMGIRGenerator.cpp
modified Marks call patchpoints created inside a try (m_tryCatchDepth) as cloningForbidden(Patchpoint) so a B3 transform cannot alias two call sites to one catch-restoration stackmap; asserts the kind is cloningForbidden.

Files Changed

  • JSTests/wasm/stress/omg-reduce-strength-select-exception-stackmap.js
  • Source/JavaScriptCore/b3/B3ReduceStrength.cpp
  • Source/JavaScriptCore/wasm/WasmOMGIRGenerator.cpp

Audit Directions

  • Clone-safety of transforms
    Audit B3 transforms that clone values (Select specialization, tail duplication) for checks against kind().isCloningForbidden().
  • Identity-bearing patchpoints
    Grep for patchpoints/values keyed by CallSiteIndex or exception stackmaps and confirm they are marked cloningForbidden.

Original Bug Report

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