CVE-2026-17672
Overview
Changed Functions
| Function | Change | Notes |
|---|---|---|
ifchromecast/media/cma/pipeline/media_pipeline_impl.cc |
modified |
Files Changed
chromecast/media/cma/pipeline/media_pipeline_impl.cc
Patch
From 2e6d61a00f581ce2c39b278ad5f08b654cf03f3f Mon Sep 17 00:00:00 2001 From: Simeon Anfinrud <[email protected]> Date: Mon, 22 Jun 2026 12:59:53 -0700 Subject: [PATCH] [chromecast] Fix Flush bypass in MediaPipelineImpl This CL addresses a state machine vulnerability where a Flush() operation could unconditionally transition the backend_state_ to INITIALIZED, bypassing the lazy initialization of the MediaPipelineBackend in StartPlayingFrom(). If a compromised renderer sent a Flush() immediately after Initialize(), the subsequent StartPlayingFrom() would skip initializing the backend and directly call Start(), violating the backend ABI contract and potentially causing memory corruption in the OEM implementation. Bug: 513375270 Test: CQ Change-Id: I3a9701676348cdd2ab9cd78e390f4dae579073f4 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7854259 Auto-Submit: Simeon Anfinrud <[email protected]> Reviewed-by: Sandeep Vijayasekar <[email protected]> Commit-Queue: Simeon Anfinrud <[email protected]> Cr-Commit-Position: refs/heads/main@{#1650515} --- diff --git a/chromecast/media/cma/pipeline/media_pipeline_impl.cc b/chromecast/media/cma/pipeline/media_pipeline_impl.cc index 39a48df9..999afb6 100644 --- a/chromecast/media/cma/pipeline/media_pipeline_impl.cc +++ b/chromecast/media/cma/pipeline/media_pipeline_impl.cc @@ -364,10 +364,12 @@ if (pending_flush_task_->audio_flushed && pending_flush_task_->video_flushed) { - // Stop the backend, so that the backend won't push their pending buffer, - // which may be invalidated later, to hardware. (b/25342604) - media_pipeline_backend_->Stop(); - backend_state_ = BACKEND_STATE_INITIALIZED; + if (backend_state_ != BACKEND_STATE_UNINITIALIZED) { + // Stop the backend, so that the backend won't push their pending buffer, + // which may be invalidated later, to hardware. (b/25342604) + media_pipeline_backend_->Stop(); + backend_state_ = BACKEND_STATE_INITIALIZED; + } metrics::CastMetricsHelper::GetInstance()->RecordApplicationEvent( "Cast.Platform.Ended");
Original Bug Report
Potential MediaPipelineBackend initialization bypass via early Flush in Chromecast CMA
Project Fortify, an experimental security project, has identified the following potential security issue. If you’re a feature owner CC-ed on this bug, please do your best to review these reports. Please see https://chromium.googlesource.com/chromium/src/+/main/docs/security/ai-generated-security-bugs-faq.md for more information.
Overview: A state machine flaw in MediaPipelineImpl allows a Flush() operation to incorrectly transition the internal backend state to INITIALIZED prematurely. This can cause subsequent playback operations to skip mandatory backend initialization, potentially leading to memory corruption in privileged vendor-specific implementations.
Affected files:
chromecast/media/cma/pipeline/media_pipeline_impl.ccmedia/mojo/services/mojo_renderer_service.ccchromecast/media/service/cast_renderer.cc
Estimated timestamp from git blame: 2016-02-18
Summary
A potential state machine vulnerability has been identified in the Chromecast CMA (Cast Multimedia Stack) pipeline. In MediaPipelineImpl, a Flush() operation can transition the backend state to BACKEND_STATE_INITIALIZED without ensuring that the underlying MediaPipelineBackend::Initialize() method has been called. This violates the mandatory initialization contract of the media backend ABI.
Technical Details
The MediaPipelineImpl class (in chromecast/media/cma/pipeline/media_pipeline_impl.cc) uses a lazy initialization pattern in StartPlayingFrom:
if (backend_state_ == BACKEND_STATE_UNINITIALIZED) {
if (!media_pipeline_backend_->Initialize()) { ... }
backend_state_ = BACKEND_STATE_INITIALIZED;
}
// Start the backend.
if (!media_pipeline_backend_->Start(time.InMicroseconds())) { ... }
However, the OnFlushDone method, which is called after a flush operation completes, unconditionally transitions the state to INITIALIZED (Reference: chromecast/media/cma/pipeline/media_pipeline_impl.cc:375):
if (pending_flush_task_->audio_flushed && pending_flush_task_->video_flushed) {
media_pipeline_backend_->Stop();
backend_state_ = BACKEND_STATE_INITIALIZED;
...
}
While there are DCHECK guards in MediaPipelineImpl::Flush and MojoRendererService::Flush intended to ensure the pipeline is in a valid state (PLAYING or PAUSED) before flushing, these checks are removed in release builds. A compromised renderer can therefore trigger a Flush() immediately after Initialize(), but before StartPlayingFrom(). This sequence causes OnFlushDone to set the state to INITIALIZED while bypassing the actual call to media_pipeline_backend_->Initialize().
Impact
The MediaPipelineBackend (defined in chromecast/public/media/media_pipeline_backend.h) is typically implemented as an OEM shared library running within the unsandboxed browser process (specifically on the privileged CastMediaThread).
Calling Stop() or Start() on an uninitialized backend violates the ABI contract and may cause the vendor implementation to dereference uninitialized handles or access unallocated memory pools. This could lead to memory corruption and potential arbitrary code execution within the privileged browser process, effectively allowing a renderer-to-browser sandbox escape.
Potential Steps to Reproduce
An attacker with control over a renderer process could potentially follow these steps:
- Acquire a handle to the
media.mojom.Rendererinterface. - Call
Initialize(client, streams)to set up the media service andMediaPipelineImpl. - Immediately call
Flush(). In a release build, this bypasses the state checks and triggersOnFlushDoneonce the (empty) pipelines are flushed. OnFlushDonesets the internalbackend_state_toINITIALIZED.- Call
StartPlayingFrom(time).MediaPipelineImplsees the state asINITIALIZED, skips the call to the backend’sInitialize(), and invokesmedia_pipeline_backend_->Start().
Suggested Fix
The OnFlushDone method should not unconditionally set the state to INITIALIZED. It should verify that the backend was previously initialized or ensure that the transition only occurs if the current state is PLAYING or PAUSED. Additionally, more robust state validation that persists in release builds should be added to the public Mojo interface boundaries.
Evaluated with Chrome root at commit: b3153093eb3c78c3e88ccf562bcbc20437a04b0e
Results so far have been promising, but there can be wrong deductions. Feel free to adjust as follows:
- If you are familiar with the severity guidelines, you may adjust the severity.
- If this is a false positive, and there’s no work to be done, please close as WAI.
- If there is work to do here but not a vulnerability, please change the issue type to Task/Bug/FR.
Data from false positives will be used to improve accuracy over time. And please feel free to reach out to me directly if you have concerns or feedback on the project.