[5] RemoteMediaPlayerProxy rejects duplicate CreateAudioSourceProvider
The GPU audio handler assumed a renderer would only ever ask once.
Rated High because a compromised WebContent process can send a duplicate CreateAudioSourceProvider to overwrite live callback closures without tapStorage->lock while a MediaToolbox thread is invoking them, freeing a RemoteAudioSourceProviderProxy mid-use in the more-privileged GPU process; escalation to a stronger primitive requires reclaiming the freed slot during the audio-thread window, which the diff does not confirm, so the reliably-reachable outcome is a GPU-process crash across the sandbox boundary.
A well-behaved WebContent process sends CreateAudioSourceProvider at most once per RemoteMediaPlayerProxy. A second message reaches AudioSourceProviderAVFObjC's setConfigureAudioStorageCallback / setAudioCallback, which overwrite the callbacks without taking tapStorage->lock while a MediaToolbox thread may be invoking them under that lock, freeing the captured RemoteAudioSourceProviderProxy mid-use. The fix rejects the duplicate message with a MESSAGE_CHECK.
Source/WebKit/GPUProcess/media/RemoteMediaPlayerProxy.cpp
LayoutTests/ipc/create-audio-source-provider-twice.html
Patch Details
A MESSAGE_CHECK(!m_remoteAudioSourceProvider, "RemoteAudioSourceProvider already created.") is added at the top of RemoteMediaPlayerProxy::createAudioSourceProvider(), rejecting the IPC message and tearing down the misbehaving connection (via MESSAGE_CHECK_WITH_MESSAGE_BASE against m_webProcessConnection) if a provider was already created for this player. A #define/#undef MESSAGE_CHECK pair binds the macro to this file's web-process connection. The rest is a regression test that drives CreateAudioSourceProvider twice through the IPC Testing API.
Missing idempotency guard on an IPC handler lets a duplicate message overwrite a live, cross-thread-referenced callback object without synchronization, freeing it mid-use.
Background
The GPU process hosts RemoteMediaPlayerProxy objects, one per media element, receiving IPC messages such as CreateAudioSourceProvider and SetShouldEnableAudioSourceProvider from WebContent. AudioSourceProviderAVFObjC is the Cocoa implementation that bridges an AVFoundation media stream into Web Audio; it installs callbacks (setConfigureAudioStorageCallback, setAudioCallback) later invoked from a MediaToolbox real-time audio thread (the "tap" callback) to pull audio samples. tapStorage->lock serializes access to that tap state between the main thread and the audio thread. MESSAGE_CHECK/MESSAGE_CHECK_WITH_MESSAGE_BASE is WebKit's IPC-hardening macro: when the assertion fails, it treats the message as malicious and tears down the offending connection. m_remoteAudioSourceProvider is the member holding the created provider, used here as the has-been-created sentinel. IPCTestingAPIEnabled exposes CoreIPC to test JavaScript so a test can send raw IPC directly, bypassing the WebContent bindings that would only send the message once.
Analysis
This is a use-after-free driven by a duplicate-message / missing-idempotency-guard combined with a cross-thread lifetime and locking gap. Before the fix, createAudioSourceProvider() assumed a well-behaved WebContent process would send CreateAudioSourceProvider at most once per proxy but did not enforce that. On a second message it re-runs the provider-setup path, reaching AudioSourceProviderAVFObjC::setConfigureAudioStorageCallback / setAudioCallback and overwriting the previously installed callback closures. Per the commit message, that overwrite happens without holding tapStorage->lock, while a MediaToolbox audio thread may concurrently be invoking those same callbacks under that lock. The overwrite releases the previously captured RemoteAudioSourceProviderProxy, dropping its last reference, while the audio thread still holds and dereferences it.
The exploit direction, modeled by the test: send CreateAudioSourceProvider for an active player, let the MediaToolbox tap thread begin invoking the installed callbacks under tapStorage->lock, then send a second CreateAudioSourceProvider. The second message overwrites the callbacks without the lock, dropping the last reference to the captured proxy while the audio thread still dereferences it. If an attacker could reclaim the freed RemoteAudioSourceProviderProxy allocation from the racing thread's window under controlled heap conditions, the in-flight callback dereference could operate on attacker-shaped memory, which could yield a type-confusion or control-flow primitive in the GPU process. At minimum it is a reliable GPU-process crash reachable from WebContent.
This vulnerability weakens the cross-process trust boundary between the WebContent sandbox and the GPU process. The security model assumes GPU-process IPC handlers are robust against malformed or out-of-sequence messages from a potentially compromised WebContent process; this handler instead trusted the sender to call it at most once. Because the vulnerable code runs in the more-privileged GPU process and triggering it only requires the ability to send IPC as WebContent, it functions as a WebContent-to-GPU sandbox-crossing bug.
The fix chooses the cheap, robust option, rejecting the duplicate outright rather than making re-installation thread-safe. Any IPC entry point that installs or replaces callbacks captured by another thread is a candidate for the same pattern.
Note: The overwrite mechanism, the absence of tapStorage->lock during that overwrite, and the mid-dereference free on the audio thread are attributed to the commit message and cannot be confirmed from the diff, which shows only the added guard and the test. The idempotency gap the guard closes is directly visible.
Audit directions
- GPU/Networking-process IPC handlers that create or install a singleton resource but lack an "already created" guard, letting a duplicate message re-run setup and overwrite live state. Audit
RemoteMediaPlayerProxyand siblingRemote*Proxyclasses inSource/WebKit/GPUProcessfor create/setup methods that mutate a member without first checking it is null; grep for handlers that assignm_remote*without a precedingMESSAGE_CHECKon that member. - Callback closures installed on the main thread but invoked from a real-time media/tap thread, replaced or destroyed without holding the thread's lock. Audit
AudioSourceProviderAVFObjC::setConfigureAudioStorageCallback/setAudioCallbackand other MediaToolbox tap-callback setters to confirm every writer takestapStorage->lock. Start by greppingWebCore/platform/audiofor setter methods whose stored lambdas capture ref-counted proxies. - "Well-behaved sender is assumed to call once" assumptions not enforced by
MESSAGE_CHECK. GrepSource/WebKit/GPUProcessandSource/WebKit/NetworkProcessfor handlers documented as single-shot and verify each has an idempotency or state-machine guard against replay. - Investigate whether other
Remote*Proxymethods that acquire scoped/singleton resources (rendering resources, sandbox extensions, layer hosting contexts) can be double-invoked from IPC, causing double-consume or double-free of the underlying resource.