CVE-2026-43734
Overview
Background
- callOnMainThreadAndWait
- A WTF helper that dispatches a task to the main thread and blocks the calling thread until it finishes, used when a non-main thread needs a main-thread-only API.
- crossThreadCopy / isolatedCopy
- WTF facilities that produce a deep, self-owned copy of a value (including its reference-counted String/Vector buffers) so it can be safely handed to another thread without sharing state.
- MediaEngineSupportParameters
- A WebCore struct bundling the content type, URL, and allowed container/codec/caption type lists used to ask a media engine whether it can play a given type.
- Non-thread-safe String/Vector
- WTF::String and Vector use reference counting and shared backing stores that are cheap to copy on one thread but unsafe to share or mutate concurrently across threads.
- Lambda capture by reference ([&])
- Captures surrounding locals by reference so the closure accesses the originals; across a thread boundary this shares the very objects the other thread must not touch.
Root Cause Analysis
MediaSource::isTypeSupported runs on a worker/script thread but must query MediaPlayer::supportsType, which has to execute on the main thread. To do so it used callOnMainThreadAndWait with a lambda that captured the local MediaEngineSupportParameters by reference ([&]) and then called MediaPlayer::supportsType(parameters) on the main thread. MediaEngineSupportParameters is a struct containing String and Vector<String>/Vector<FourCC> members (type, url, contentTypesRequiringHardwareSupport, allowedMediaContainerTypes/CodecTypes, etc.). These WTF String/Vector types are reference-counted/heap-backed but are NOT thread-safe to share across threads by reference: passing them by reference means the main thread touches the same underlying buffers that the originating thread owns, violating the invariant that cross-thread work must operate on data that has been deep-copied (crossThreadCopy / isolatedCopy) into thread-owned storage. Although callOnMainThreadAndWait blocks the caller until the main-thread task completes, capturing by reference still lets the two threads concurrently reference the same non-thread-safe String/Vector internals during the hand-off, and any implicit ref/deref, copy, or internal mutation of those shared buffers from the main thread races with the worker thread’s ownership, leading to use-after-free / heap corruption of the string buffers.
The fix changes the capture to [&supported, parameters = crossThreadCopy(WTF::move(parameters))], deep-copying the parameters into a thread-safe isolated copy that the main-thread lambda solely owns, so no non-thread-safe buffer is shared across the boundary. To support that, a new MediaEngineSupportParameters::isolatedCopy() && rvalue-qualified method is added in MediaPlayer.cpp/.h that crossThreadCopy()s each string/vector member and moves the trivially-copyable/plain members, giving crossThreadCopy a correct per-field deep-copy for this struct.
The restored invariant is: values handed to another thread must be isolated copies with no shared reference-counted state.
Attack Path
- Run isTypeSupported off the main thread From maliciously crafted web content, invoke MediaSource.isTypeSupported(…) (or a code path reaching MediaSource::isTypeSupported) from a Worker or other non-main script thread so the callOnMainThreadAndWait hand-off is exercised.
- Supply complex type parameters Pass a content type / codec string that populates the String and Vector members of MediaEngineSupportParameters (type, allowed container/codec type lists), maximizing the reference-counted buffers shared by reference across the thread boundary.
- Race the shared buffers Cause the worker thread and the main thread to touch the same non-thread-safe String/Vector internals during the hand-off, so ref/deref or buffer access on one thread races the other’s ownership (inference: precise timing/interleaving needed to win the race is not shown by the diff).
- Trigger use-after-free The race frees or corrupts a String/Vector backing buffer while the other thread still references it, producing a use-after-free within WebCore’s media pipeline.
- Crash the process Per the advisory this yields an unexpected process crash; escalation beyond a crash would require additional heap-grooming and a separate corruption primitive not established by this commit.
Impact Assessment
Changed Functions
| Function | Change | Notes |
|---|---|---|
MediaSource::isTypeSupportedSource/WebCore/Modules/mediasource/MediaSource.cpp |
modified | Changed the callOnMainThreadAndWait lambda from capturing parameters by reference ([&]) to capturing a deep isolated copy ([&supported, parameters = crossThreadCopy(WTF::move(parameters))]) so the main thread no longer shares the caller's non-thread-safe String/Vector buffers. |
MediaEngineSupportParameters::isolatedCopy() &&Source/WebCore/platform/graphics/MediaPlayer.cpp |
added | New rvalue-qualified method that crossThreadCopy()s each String/Vector member (type, url, contentTypesRequiringHardwareSupport, allowed container/codec type lists) and moves the plain members, providing a correct cross-thread deep copy of the struct. |
MediaEngineSupportParameters (struct declaration)Source/WebCore/platform/graphics/MediaPlayer.h |
modified | Declared WARN_UNUSED_RETURN WEBCORE_EXPORT MediaEngineSupportParameters isolatedCopy() && so crossThreadCopy can produce a thread-owned copy of the parameters. |
Files Changed
Source/WebCore/Modules/mediasource/MediaSource.cppSource/WebCore/platform/graphics/MediaPlayer.cppSource/WebCore/platform/graphics/MediaPlayer.h
Audit Directions
- Other by-reference captures into callOnMainThread*Grep WebCore for callOnMainThreadAndWait and callOnMainThread lambdas that capture [&] or [&, …] and inspect whether any captured local holds String/Vector/RefPtr state shared across the boundary rather than a crossThreadCopy.
- Structs handed cross-thread without isolatedCopySearch for crossThreadCopy(…) usages and, conversely, structs with String/Vector members passed into cross-thread dispatch (dispatchToMainThread, Function, CrossThreadTask) that lack an isolatedCopy()&& overload; a missing isolatedCopy is the tell.
- Media parameter plumbing across threadsAudit MediaSource, SourceBuffer, and MediaPlayer paths that bridge worker/script threads to the main thread with MediaEngineSupportParameters or similar content-type structs, verifying each hand-off deep-copies rather than referencing caller-owned buffers.