← All issues

Don't register WebM / MSE-AVF media players for GPU-process playback under MediaContainment

514ac25

WebKit splits media across the WebContent process (JS, demuxing), the GPU process (decoding, rendering), and a WebContent-side remote proxy (MediaPlayerPrivateRemote). When MediaContainment is enabled, WebM and MSE-AVF engines demux in WebContent and only the renderer lives in GPU, so instantiating the full MediaPlayerPrivate in GPU is both unnecessary and a defense-in-depth gap. Previously a single MESSAGE_CHECK in createMediaPlayer was the explicit IPC guard rejecting those instantiations; codec capability queries (canDecodeExtendedType) shared the same engine registry with no way to distinguish "can answer queries" from "can be instantiated for playback".

Source/WebCore/platform/graphics/MediaPlayerEnums.h

+enum class MediaPlayerScope : uint8_t {
+ Playback,
+ Supports,
+};

Source/WebKit/GPUProcess/media/RemoteMediaPlayerManagerProxy.cpp

-#if PLATFORM(COCOA)
- MESSAGE_CHECK(!connection->sharedPreferencesForWebProcessValue().mediaContainmentEnabled
- || engineIdentifier == MediaPlayerEnums::MediaEngineIdentifier::AVFoundation
- || engineIdentifier == MediaPlayerEnums::MediaEngineIdentifier::WirelessPlayback);
-#endif
+ MESSAGE_CHECK(playbackEngineForConnection(engineIdentifier));

This commit replaces the hand-maintained allowlist with registry-based scope filtering. Each MediaPlayerPrivate now declares its own MediaPlayerScope (Playback vs Supports), and a new playbackEngineForConnection helper filters all GPU-process engine lookups by scope and MediaContainmentEnabled state, preventing WebM and MSE-AVF engines from being instantiated for GPU playback when MediaContainment is active while still letting them answer codec queries.

This restructures a GPU-process privilege boundary: the explicit MESSAGE_CHECK IPC guard is gone, replaced by an implicit registry contract that must be upheld correctly at every call site — a larger and more subtle attack surface.

MediaContainmentEnabled flows from the connection's stored preference — if it can be set or read inconsistently between WebContent and GPU (TOCTOU during connection setup, or a connection that changes containment state after engines are registered), scope filtering produces wrong results silently. playbackEngineForConnection is now the sole chokepoint for all GPU-side playback engine lookups; any call site skipping it or querying with the wrong scope loses the old MESSAGE_CHECK entirely — audit whether getSupportedTypes, supportsTypeAndCodecs, and supportsKeySystem all route through it. canDecodeExtendedType now queries with Supports scope — an engine answering codec queries from GPU while restricted from instantiation may still expose fuzzable codepaths. Finally, the MockMSE registration branch changed its conditional logic; verify mock mode does not register engines in GPU that production mode forbids.