CVE-2026-7339
Overview
Changed Functions
| Function | Change | Notes |
|---|---|---|
ifmedia/webrtc/audio_processor.cc |
modified |
Files Changed
media/webrtc/audio_processor.cc
Patch
From 8708a22598eb84809063a257db7ffdcede2384ae Mon Sep 17 00:00:00 2001 From: Tomas Gunnarsson <[email protected]> Date: Mon, 30 Mar 2026 00:03:07 -0700 Subject: [PATCH] Upgrade DCHECK_EQ to CHECK_EQ in audio_processor.cc. This ensures that the frame size check is performed in all build configurations, not just debug builds. Bug: 493957495 Change-Id: I18bdcf58ef136d0d65c6a8cebd083dabe73299ec Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7710554 Reviewed-by: Per Åhgren <[email protected]> Auto-Submit: Tomas Gunnarsson <[email protected]> Commit-Queue: Per Åhgren <[email protected]> Cr-Commit-Position: refs/heads/main@{#1606910} --- diff --git a/media/webrtc/audio_processor.cc b/media/webrtc/audio_processor.cc index 66272c1..4e324e2 100644 --- a/media/webrtc/audio_processor.cc +++ b/media/webrtc/audio_processor.cc @@ -289,7 +289,7 @@ CHECK(input_format_.IsValid()); CHECK(output_format_.IsValid()); if (webrtc_audio_processing_) { - DCHECK_EQ( + CHECK_EQ( webrtc::AudioProcessing::GetFrameSize(output_format_.sample_rate()), output_format_.frames_per_buffer()); }
Original Bug Report
DCHECK-only validation of WebRTC APM output buffer size leads to heap buffer overflow from compromised renderer
DCHECK-only validation of WebRTC APM output buffer size leads to heap buffer overflow from compromised renderer
Summary
A compromised renderer can cause a heap buffer overflow in the audio service process by sending crafted AudioParameters through the blink.mojom.RendererAudioInputStreamFactory.CreateStream Mojo interface. The constraint that the output buffer’s frames_per_buffer must equal sample_rate / 100 when WebRTC audio processing is enabled is enforced only by a DCHECK_EQ, which is compiled out in release builds. A renderer that supplies frames_per_buffer=1 with sample_rate=48000 causes the audio service to allocate a 1-frame output buffer while the WebRTC Audio Processing Module writes 480 frames into it, overflowing the heap allocation by approximately 1916 bytes. All desktop platforms are affected.
Bisect
Introducing Commit: d33edbcc63a9f12be07f68e392a6126d1a3b370c
- Date: 2021-12-09
- Author: Sam Zackrisson
- Review: https://chromium-review.googlesource.com/c/chromium/src/+/3309225
Root Cause
When a renderer requests an audio input stream with WebRTC audio processing enabled, it supplies media::AudioParameters that specify the desired output format. These parameters travel from the renderer through RenderFrameAudioInputStreamFactory, ForwardingAudioStreamFactory, audio::StreamFactory, audio::InputStream, and audio::InputController into media::AudioProcessor without any CHECK-level validation of the relationship between sample_rate and frames_per_buffer.
The AudioProcessor constructor contains the following assertion:
// media/webrtc/audio_processor.cc:287-293
CHECK(input_format_.IsValid());
CHECK(output_format_.IsValid());
if (webrtc_audio_processing_) {
DCHECK_EQ(
webrtc::AudioProcessing::GetFrameSize(output_format_.sample_rate()),
output_format_.frames_per_buffer());
}
The two CHECK calls validate IsValid(), which only requires frames_per_buffer > 0 and frames_per_buffer <= 768000. A parameter set of {sample_rate=48000, frames_per_buffer=1} passes this validation. The subsequent DCHECK_EQ verifies the 10ms alignment requirement, but this is stripped from release builds.
The constructor then allocates the output buffer using the unchecked frames_per_buffer:
// media/webrtc/audio_processor.cc:323-326
if (webrtc_audio_processing_) {
output_bus_ = std::make_unique<AudioProcessorCaptureBus>(
output_format_.channels(), output_format.frames_per_buffer());
}
With frames_per_buffer=1, this allocates a single-frame buffer. When audio data arrives, ProcessData constructs the APM output configuration from the sample rate, which determines a 480-frame write size:
// media/webrtc/audio_processor.cc:552-557
const webrtc::StreamConfig apm_output_config = webrtc::StreamConfig(
output_format_.sample_rate(), num_apm_output_channels);
int err =
ap->ProcessStream(process_ptrs.data(), CreateStreamConfig(input_format_),
apm_output_config, output_bus->channel_ptrs().data());
webrtc::AudioProcessing::GetFrameSize(48000) returns 480. The ProcessStream call writes 480 float samples through the raw float* channel pointers, which point into the 1-frame buffer. This produces a heap buffer overflow of 479 floats, or 1916 bytes.
The write target is a raw float* array inside an AudioBus allocation. No libc++ hardening, PartitionAlloc bucket isolation, or MiraclePtr protection applies to this access path.
Reproduce
Tested at commit d0f83d769eeed0b61ffc7d3c15172b2c257acf4e on macOS (arm64).
Build configuration (out/asan-release/args.gn):
is_asan = true
is_debug = false
dcheck_always_on = false
is_component_build = true
target_cpu = "arm64"
Apply the renderer-side patch and build:
git apply issue_mojo034/patch.diff
autoninja -C ~/chromium/src/out/asan-release chrome
Launch:
ASAN_OPTIONS=detect_odr_violation=0 ~/chromium/src/out/asan-release/Chromium.app/Contents/MacOS/Chromium \
--user-data-dir=/tmp/poc-audio \
--use-fake-device-for-media-stream \
--use-fake-ui-for-media-stream \
issue_mojo034/poc.html
The audio service thread crashes within one second of the page loading.
==62908==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x60300008f750 at pc 0x0001170fa3d0 bp 0x00030a04e2a0 sp 0x00030a04e298
WRITE of size 16 at 0x60300008f750 thread T13
#0 webrtc::FloatS16ToFloat(float const*, unsigned long, float*)
#1 webrtc::AudioBuffer::CopyTo(webrtc::StreamConfig const&, float* const*)
#2 webrtc::AudioProcessingImpl::ProcessStream(float const* const*, webrtc::StreamConfig const&, webrtc::StreamConfig const&, float* const*)
#3 media::AudioProcessor::ProcessData(...)
#4 media::AudioProcessor::ProcessCapturedAudio(media::AudioBus const&, base::TimeTicks, int, double)
#5 audio::AudioProcessorHandler (via callback)
#6 audio::ProcessingAudioFifo::ProcessAudioLoop(base::WaitableEvent*)
0x60300008f750 is located 0 bytes after 16-byte region [0x60300008f740,0x60300008f750)
allocated by thread T0 here:
#0 __asan_memmove
#1 base::AlignedAlloc(unsigned long, unsigned long)
#2 base::AlignedUninit<float>(unsigned long, unsigned long)
#3 media::AudioBus::AudioBus(int, int)
#4 media::AudioProcessor::AudioProcessor(...)
#5 media::AudioProcessor::Create(...)
#6 audio::AudioProcessorHandler::AudioProcessorHandler(...)
#7 audio::InputController::MaybeSetUpAudioProcessing(...)
#8 audio::InputController::InputController(...)
#9 audio::InputController::Create(...)
#10 audio::InputStream::InputStream(...)
#11 audio::StreamFactory::CreateInputStream(...)
#12 media::mojom::AudioStreamFactoryStubDispatch::AcceptWithResponder(...)
Thread T13 created by T0 here:
#5 audio::InputController::Record()
#6 audio::InputStream::Record()
#7 media::mojom::AudioInputStreamStubDispatch::Accept(...)
SUMMARY: AddressSanitizer: heap-buffer-overflow in webrtc::FloatS16ToFloat(float const*, unsigned long, float*)
Credit
Please use c6eed09fc8b174b0f3eebedcceb1e792 as the credit for this vulnerability. Thank you.