← WebKit — 2026-W35

2c0289313661d61c6086d958f582c13d32ecf98a  Use-after-free in BaseAudioContext::decodeAudioData()

severity medium class Race confidence 0.5 signal score 12.37 Source/WebCore/Modules
Primitive: decodeAudioData shared a JS ArrayBuffer backing store with a worker thread instead of copying
Triage note: The non-legacy branch copies audioData->span() into a Vector/SharedBuffer before AsyncAudioDecoder::decodeAsync instead of pinning the ArrayBuffer and handing its backing store to the decode thread. Removes cross-thread access to the live JS buffer (a data-race/TOCTOU hazard), but pin() already blocked detach so exploitability is unclear.
Structural signals: smartptr_member_added (+4.87), null_guard (+1.2), msg_strong (+3.0), msg_medium (+2.0), surgical (+1.3)

Commit message

Use-after-free in BaseAudioContext::decodeAudioData()
rdar://182930759
https://bugs.webkit.org/show_bug.cgi?id=322671

Reviewed by Jean-Yves Avenard.

An ArrayBuffer passed into decodeAudioData() is first pin()'d to prevent that data from
being transferred and mutated to a Worker. However, if that ArrayBuffer originated from
a WASM Memory object, it can be resized and therefore have its storage invalidated while
the decoder is parsing the contents, causing a UAF.

Copy the incoming data into a new SharedBuffer, and update the signature of decodeAsync()
to take a SharedBuffer rather than an ArrayBuffer.

Test: sar3/webaudio/decode-audio-data-wasm-memory-grow-crash.html

* LayoutTests/sar3/webaudio/decode-audio-data-wasm-memory-grow-crash-expected.txt: Added.
* LayoutTests/sar3/webaudio/decode-audio-data-wasm-memory-grow-crash.html: Added.
* Source/WebCore/Modules/webaudio/AsyncAudioDecoder.cpp:
(WebCore::AsyncAudioDecoder::decodeAsync):
* Source/WebCore/Modules/webaudio/AsyncAudioDecoder.h:
* Source/WebCore/Modules/webaudio/BaseAudioContext.cpp:

Identifier: 316606.555@safari-7625-branch

Before / after

Loading diff…