CVE-2026-13801
Overview
Changed Functions
| Function | Change | Notes |
|---|---|---|
playback_rate_chromecast/media/audio/audio_fader.cc |
modified |
Files Changed
chromecast/media/audio/audio_fader.ccchromecast/media/audio/cast_audio_bus.cc
Patch
From 52e0efb0d221766111a85558a5da7bde7b652242 Mon Sep 17 00:00:00 2001 From: Simeon Anfinrud <[email protected]> Date: Mon, 11 May 2026 20:56:57 -0700 Subject: [PATCH] [chromecast] Fix Integer overflow in CastAudioBus allocation Use base::CheckMul to safely calculate the allocation size in CastAudioBus::Create, preventing integer overflow and subsequent heap buffer overflows. Added an upper bound check for fade_frames_ in AudioFader to prevent excessively large allocations. Bug: 500587568 Test: Compiled and passed unit tests. Change-Id: I91ffee3b96117578f9ef1de3070ffb879236a39c Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7765496 Commit-Queue: Sandeep Vijayasekar <[email protected]> Auto-Submit: Simeon Anfinrud <[email protected]> Reviewed-by: Sandeep Vijayasekar <[email protected]> Cr-Commit-Position: refs/heads/main@{#1629040} --- diff --git a/chromecast/media/audio/audio_fader.cc b/chromecast/media/audio/audio_fader.cc index bf2eb677..563a78579 100644 --- a/chromecast/media/audio/audio_fader.cc +++ b/chromecast/media/audio/audio_fader.cc @@ -37,7 +37,10 @@ sample_rate_(provider_->sample_rate()), playback_rate_(playback_rate) { DCHECK(provider_); - DCHECK_GT(fade_frames_, 0); + CHECK_GT(fade_frames_, 0); + // Cap the maximum fade length to 10 seconds at 192kHz to prevent + // excessive memory allocation and potential integer overflows later. + CHECK_LT(fade_frames_, 192000 * 10); DCHECK_GT(num_channels_, 0u); DCHECK_LE(num_channels_, kMaxChannels); DCHECK_GT(sample_rate_, 0); diff --git a/chromecast/media/audio/cast_audio_bus.cc b/chromecast/media/audio/cast_audio_bus.cc index b70e8cc..505b579 100644 --- a/chromecast/media/audio/cast_audio_bus.cc +++ b/chromecast/media/audio/cast_audio_bus.cc @@ -7,17 +7,24 @@ #include <algorithm> #include <cstring> +#include "base/check_op.h" #include "base/compiler_specific.h" #include "base/memory/ptr_util.h" +#include "base/numerics/checked_math.h" namespace chromecast { namespace media { CastAudioBus::CastAudioBus(int channels, int frames) : frames_(frames) { - data_.reset(new float[channels * frames]); + CHECK_GE(channels, 0); + CHECK_GE(frames, 0); + size_t size = base::CheckMul(static_cast<size_t>(channels), + static_cast<size_t>(frames)) + .ValueOrDie(); + data_.reset(new float[size]); channel_data_.reserve(channels); for (int i = 0; i < channels; ++i) - channel_data_.push_back(UNSAFE_TODO(data_.get() + i * frames)); + channel_data_.push_back(UNSAFE_TODO(data_.get() + static_cast<size_t>(i) * frames)); } CastAudioBus::~CastAudioBus() = default;
Original Bug Report
Potential Integer overflow in CastAudioBus allocation allows heap overflow in Chromecast mixer
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 without the security team.
Overview: An integer overflow in the CastAudioBus constructor allows for an undersized heap allocation when a large fade_frames value is provided via the unsandboxed Chromecast mixer service. An attacker connecting via the unauthenticated Unix Domain Socket can exploit this on 32-bit platforms to cause a massive, attacker-controlled heap buffer overflow, potentially leading to local privilege escalation or sandbox escape.
Affected files:
chromecast/media/audio/cast_audio_bus.ccchromecast/media/audio/audio_fader.ccchromecast/media/cma/backend/mixer/mixer_input_connection.ccchromecast/media/audio/net/audio_socket_service_uds.cc
Estimated timestamp from git blame: 2025-11-18
Background
The Chromecast mixer service (typically running as an unsandboxed process) exposes an abstract Unix Domain Socket (UDS) at /tmp/mixer-service that accepts connections via AudioSocketService. The authentication callback for this socket unconditionally returns true (chromecast/media/audio/net/audio_socket_service_uds.cc:65), allowing any unprivileged process or sandboxed renderer to connect.
Vulnerability Mechanism
When an attacker connects and sends a mixer_service::Generic message, they can initialize an audio stream using OutputStreamParams. The fade_frames parameter in this message is extracted without any maximum bounds checking (chromecast/media/cma/backend/mixer/mixer_input_connection.cc:394-398).
This unvalidated fade_frames value is passed down to instantiate an AudioFader and ultimately a CastAudioBus. In the CastAudioBus constructor, an allocation size is calculated using a 32-bit signed integer multiplication:
// chromecast/media/audio/cast_audio_bus.cc
CastAudioBus::CastAudioBus(int channels, int frames) : frames_(frames) {
data_.reset(new float[channels * frames]);
channel_data_.reserve(channels);
for (int i = 0; i < channels; ++i)
channel_data_.push_back(UNSAFE_TODO(data_.get() + i * frames));
}
If an attacker sets channels to 32 (the maximum allowed) and frames to 1,073,741,825 (0x40000001), the multiplication 32 * 1,073,741,825 overflows to 32. This results in a tiny 128-byte allocation (new float[32]).
On 32-bit architectures (standard for Chromecast ARM devices), the subsequent pointer arithmetic data_.get() + i * frames scales the frames by sizeof(float). For channel 1, this offset is 1,073,741,825 * 4, which wraps modulo 2^32 to exactly 4 bytes. Consequently, all 32 channel pointers alias safely into the same tiny 128-byte heap buffer.
During audio playback, AudioFader attempts to fill its massive buffer by requesting fade_frames_ - buffered_frames_ (roughly 1 billion frames) from its provider. This triggers MixerInputConnection::FillFromQueue, where std::copy_n copies the attacker’s queued audio payloads directly into the undersized channel_data_ pointers. Because the attacker’s payloads are larger than the 128-byte allocation, this results in a severe out-of-bounds heap write.
Potential Attacker Steps (Suggested)
Note: These are theoretical steps based on source code analysis.
- Connect to the mixer service UDS socket at
/tmp/mixer-service. - Send a
mixer_service::Genericmessage withOutputStreamParams. - Set
num_channelsto32andfade_framesto0x40000001. - Configure
timestamped_audio_configwithnever_crop = trueto bypass cropping logic inMixerInputConnection::FillTimestampedAudio. - Stream thousands of frames of raw audio data containing a malicious payload (e.g., fake vtable pointers or ROP chains).
- When the StreamMixer engine requests playback data, the massive
std::copy_ntriggers, overwriting adjacent heap metadata and objects, leading to RCE within the mixer service.
Suggested Fix
- Validate
fade_frameswhen parsingOutputStreamParamsto ensure it falls within reasonable system limits. - Use
base::CheckedNumericinsideCastAudioBus::Createand theCastAudioBusconstructor to prevent integer overflows during size calculations, returning a failure or crashing safely if an overflow is detected.
Evaluated with Chrome root at commit: 137d451a126685dd5010e6609db9f6d4a78d8234
Results so far have been promising, but there can be wrong deductions. If this proves to be a false positive, please close as WAI; 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.