CVE-2025-43421
Overview
Background
- Allocation sinking
- A JIT optimization that removes or delays an object/array allocation when escape analysis proves the object is not observable, reconstructing it only where needed.
- Materialization
- The point where a previously sunk allocation is actually built in memory, typically on an OSR-exit or merge path that requires a concrete object.
- OSR exit
- On-stack replacement that bails from JIT-compiled code back to a lower tier, a common site where sunk allocations must be materialized correctly.
- Indexing type / butterfly
- JSC array metadata describing element storage kind and the out-of-line backing store; an array whose indexing type or length is inconsistent leads to OOB or type-confused access.
- JSC runtime Option
- A compile-time-listed, runtime-togglable flag in OptionsList.h; flipping its default changes engine behavior for all builds that do not override it.
Root Cause Analysis
The patch is a one-line change to Source/JavaScriptCore/runtime/OptionsList.h that flips the default value of the JSC runtime option useArrayAllocationSinking from true to false. Array allocation sinking is a DFG/FTL JIT optimization phase (implemented in Source/JavaScriptCore/dfg/DFGArrayAllocationSinkingPhase / the broader object-allocation-sinking machinery) that proves an allocated array does not escape and therefore removes or delays (sinks) the actual heap allocation, reconstructing (materializing) the object only on paths that need it, such as OSR exit. The vulnerable code is NOT in this diff; the diff only shows the mitigation of turning the optimization off by default. Inference: the underlying defect is a soundness bug in the allocation-sinking analysis or materialization logic, where the phase incorrectly concludes an array does not escape (or materializes it with wrong length/contents/type), so the optimized code operates on an object that either was never correctly allocated or was reconstructed with inconsistent metadata. The violated invariant is that a sunk allocation must be observationally identical to a real allocation for every path that can observe it: same butterfly/length, same indexing type, same initialization. When that invariant breaks, JIT-compiled code reads or writes through a phantom or mis-materialized array, producing the unexpected process crash noted in the advisory.
The fix is blunt and conservative: rather than repairing the analysis, WebKit disabled the entire optimization by default, so no array allocation is ever sunk and the miscompilation path is unreachable. Because the fix is a default flip and not a localized correctness patch, the precise faulty predicate cannot be read off this diff and any statement about the exact escape-analysis mistake is inference, not established by the commit. The Normal option class means it remains togglable, but production builds now take the safe path.
Attack Path
- Deliver JS that triggers FTL/DFG tiering The attacker serves web content whose JavaScript runs a hot loop that allocates and manipulates arrays so the function is tiered up into the DFG/FTL JIT where the array-allocation-sinking phase runs.
- Shape code so an array is judged non-escaping Inference: craft control/data flow (e.g. conditional escapes, OSR-exit edges, or phi merges of array allocations) that the escape analysis mis-analyzes, so a genuinely-observable array allocation is sunk.
- Force materialization on a mishandled path Inference: drive execution down the path (often an OSR exit or a merge point) where the sunk allocation is materialized with incorrect length, indexing type, or uninitialized backing store.
- Observe the mis-materialized object Read or write elements of the array whose in-memory representation no longer matches its logical type/length, yielding out-of-bounds access or corrupted object state.
- Crash (established) / escalate (background) The commit establishes only an unexpected WebContent crash. Standard escalation background: an OOB/type-inconsistent array primitive in JSC is the classic starting point for addrof/fakeobj and arbitrary read/write, but nothing in this diff demonstrates that reliability.
Impact Assessment
Changed Functions
| Function | Change | Notes |
|---|---|---|
useArrayAllocationSinking (option default)Source/JavaScriptCore/runtime/OptionsList.h |
modified | Default value changed from true to false, disabling the array-allocation-sinking JIT optimization by default; the buggy phase code itself is not in this diff. |
Files Changed
Source/JavaScriptCore/runtime/OptionsList.h
Audit Directions
- Read the allocation-sinking phase directlyInspect Source/JavaScriptCore/dfg/DFGObjectAllocationSinkingPhase.cpp and any array-specific sinking logic for escape-analysis edge cases; grep for materialize, PhantomNewArray, PhantomCreateActivation, and handling of OSR-exit and phi merges of allocation nodes.
- Cross-check other sunk allocation kindsThe same soundness class can affect non-array sunk allocations; grep for Phantom* node kinds and the promoted-heap/materialization code to see whether object, arguments, or activation sinking share the mishandled path.
- Audit other default-true optimization flagsSearch OptionsList.h for recently-flipped or historically-flipped Normal Bool optimization options (grep useOMGInlining, useArray*, useConcurrent*) to find optimizations disabled as covert security mitigations and re-examine their phases.
- Correlate option flip with regressionsDiff the JIT phase files around this commit range and look for follow-up commits re-enabling useArrayAllocationSinking with an actual analysis fix; the real root-cause change reveals the exact violated invariant to search for in sibling phases.