Overview

Medium
Severity
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactHeap buffer overflow in WebRTC
DescriptionHeap buffer overflow in WebRTC
ComponentWebRTC
Bug ClassOOB
Tracker493957495
Fix commit8708a22598eb (chromium/src) +1/-1
CISA KEVNot listed
Creditedc6eed09fc8b174b0f3eebedcceb1e792
Disclosed2026-04-28

Changed Functions

FunctionChangeNotes
if
media/webrtc/audio_processor.cc
modified

Files Changed

  • media/webrtc/audio_processor.cc
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());
   }
Loading diff…

Original Bug Report

reported by [email protected]

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

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.

View on issue tracker