← All issues

[11] [JSC] Use span's length in genericTypedArrayViewProtoFuncSortImpl

Severity: High | Component: JSC TypedArray prototype | c852586

Rated High because the diff fixes a TOCTOU on a GSAB-backed TypedArray's length: a parallel grow desynchronizes length() from typedSpan().size(), and the sort body uses both — an OOB during element copy.

genericTypedArrayViewProtoFuncSortImpl performed two independent length reads — thisObject->length() and thisObject->typedSpan(). With a Growable SharedArrayBuffer backing, another agent's grow() between the reads could make them disagree.

Source/JavaScriptCore/runtime/JSGenericTypedArrayViewPrototypeFunctions.h

- size_t length = thisObject->length();
+ auto originalSpan = thisObject->typedSpan();
+ size_t length = originalSpan.size();
+
if (length < 2)
return JSValue::encode(thisObject);
 
- auto originalSpan = thisObject->typedSpan();
-
Vector<typename ViewClass::ElementType, 256> vector;

The order is swapped: originalSpan is constructed first and length is derived from originalSpan.size(). Single snapshot, single source of truth.

TOCTOU on a shared-memory length: deriving two values from two independent reads of the same race-prone quantity instead of a single snapshot.

A Growable SharedArrayBuffer (constructed with maxByteLength) can be grown via SharedArrayBuffer.prototype.grow. A length-tracking TypedArray view over a GSAB returns a length derived from the current SAB byte length; SABs are shared across agents (main thread and Workers), so each length re-derivation reads a value that can change underneath the implementation. std::span here is a {pointer, size} pair captured at call time. %TypedArray%.prototype.sort accepts a user comparator and is implemented in C++ by copying into a work buffer, sorting, then copying back.

length reflected the pre-grow size while originalSpan reflected post-grow. The sort body uses both: the work vector is sized from length, while the span is the source/destination of element copies and sort callbacks. The invariant length == originalSpan.size() no longer held.

🔒

The concurrency and memory-consistency implications of this race are analyzed in depth, alongside the exploitation feasibility from web content.

Subscribe to read more

🔒

Multiple reusable audit patterns identified across JSC's TypedArray prototype implementations, with concrete starting points for variant discovery.

Subscribe to read more