CVE-2025-43429
Overview
Background
- String.prototype.normalize
- JS API that Unicode-normalizes a string (NFC/NFD/NFKC/NFKD) via ICU.
- ICU preflight pattern
- Call a converter with a zero-length buffer to learn the needed size, then allocate and call again; relies on correct length math.
- U_MEMORY_ALLOCATION_ERROR
- ICU status code signalling an internal allocation failure that callers must check rather than assume grow-to-fit.
Root Cause Analysis
This fixes an integer overflow reachable through String.prototype.normalize. In StringPrototype.cpp’s normalize(), JSC calls ICU’s unorm2_normalize in a preflight/allocate/normalize pattern: it first calls with a zero-length output buffer to learn the required length (normalizedStringLength), then allocates and normalizes for real. ICU computes internal buffer lengths with 32-bit arithmetic, and for a sufficiently large input string those length calculations can overflow, so ICU either mis-sizes buffers or reports a memory-allocation error that the caller ignored (the code only ASSERTed needsToGrowToProduceBuffer(status)).
The fix adds two guards: a pre-check that rejects inputs of length >= 2^30 with an OutOfMemoryError before calling ICU at all (the comment cites rdar://160634825 and the ICU overflow), and a check of the ICU status via the new isICUMemoryAllocationError(status) helper (U_MEMORY_ALLOCATION_ERROR) after the preflight call, again throwing OutOfMemoryError instead of proceeding.
The restored invariant is that JSC never continues normalization when the input is large enough to overflow ICU’s length math or when ICU signals an allocation failure; it converts those conditions into a clean JS exception. The vulnerable overflow itself is inside ICU (not shown), so the precise corrupted computation is inferred, but the patch establishes the trigger (huge strings) and the missing status handling.
Attack Path
- Build a huge string Construct a JS string near or above 2^30 code units.
- Call normalize() Invoke str.normalize(form) so JSC hands the oversized length to ICU’s unorm2_normalize preflight.
- Overflow ICU length math ICU’s 32-bit buffer-length calculation overflows / signals allocation failure, previously unhandled beyond an ASSERT.
- Crash the process The mis-sized buffer or ignored error path leads to a process crash in WebContent.
Impact Assessment
Changed Functions
| Function | Change | Notes |
|---|---|---|
normalizeSource/JavaScriptCore/runtime/StringPrototype.cpp |
modified | Adds an early length>=2^30 OutOfMemoryError guard and checks isICUMemoryAllocationError(status) after the preflight unorm2_normalize call, throwing instead of proceeding. |
isICUMemoryAllocationErrorSource/WTF/wtf/unicode/icu/ICUHelpers.h |
added | New helper returning true for U_MEMORY_ALLOCATION_ERROR, exported and used to detect ICU allocation failures. |
Files Changed
Source/JavaScriptCore/runtime/StringPrototype.cppSource/WTF/wtf/unicode/icu/ICUHelpers.h
Audit Directions
- Other ICU call sitesGrep for unorm2_, ucol_, u_str* and other ICU calls that use the preflight/grow pattern and check whether they handle U_MEMORY_ALLOCATION_ERROR (needsToGrowToProduceBuffer only).
- Length preconditionsLook for JSC string operations that forward view->length() to a 32-bit C API without a size cap, especially near normalization, collation, and case mapping.