Overview

Medium
Severity
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactBuffer overflow in Media
DescriptionBuffer overflow in Media
ComponentMedia
Bug ClassOOB
Tracker504356442
Fix commit493d2dfa61ff (chromium/src) +19/-19
CISA KEVNot listed
CreditedGoogle
Disclosed2026-08-25

Changed Functions

FunctionChangeNotes
if
media/ffmpeg/ffmpeg_common.cc
modified
TEST_P
media/filters/audio_file_reader_unittest.cc
modified

Files Changed

  • DEPS
  • media/ffmpeg/ffmpeg_common.cc
  • media/filters/audio_file_reader_unittest.cc
  • media/test/pipeline_integration_test.cc
  • third_party/ffmpeg
From 493d2dfa61ffb1e9cf218c24e356f31e1b76b66a Mon Sep 17 00:00:00 2001
From: Eugene Zemtsov <eugene@chromium.org>
Date: Thu, 16 Jul 2026 14:17:41 -0700
Subject: [PATCH] Roll ffmpeg for M152

Fix tests and glue code to account for newly introduced in ffmpeg AAC
initial_padding

Bug: 527501449, 504356442, 403330011
Change-Id: I3471e8e4621c037958316ebc09cd38dd59ce110f
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/8066846
Reviewed-by: Dale Curtis <dalecurtis@chromium.org>
Commit-Queue: Eugene Zemtsov <eugene@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1663509}
---

diff --git a/DEPS b/DEPS
index 706eb209..8c596f1 100644
--- a/DEPS
+++ b/DEPS
@@ -523,7 +523,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling ffmpeg
   # and whatever else without interference from each other.
-  'ffmpeg_revision': 'fcf00a65aa4168c2ae1ce6e55f59e8bc1edd6c78',
+  'ffmpeg_revision': '2b68d2babae73714846961fb0ee47e3b3d2e39a9',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling webpagereplay
   # and whatever else without interference from each other.
diff --git a/media/ffmpeg/ffmpeg_common.cc b/media/ffmpeg/ffmpeg_common.cc
index e5ebfb17..280dce68 100644
--- a/media/ffmpeg/ffmpeg_common.cc
+++ b/media/ffmpeg/ffmpeg_common.cc
@@ -443,10 +443,21 @@
         .copy_from_nonoverlapping(AVCodecContextExtraDataToSpan(codec_context));
   }
 
+  // FFmpeg exports AAC edit list padding in
+  // AVCodecParameters::initial_padding, which propagates to
+  // codec_context->delay. AAC does not have a pipeline decoder delay, and
+  // this padding is already discarded using container-level discard padding.
+  // Pass 0 here to prevent AudioDiscardHelper from treating it as decoder
+  // delay and failing.
+  int codec_delay = codec_context->delay;
+  if (codec == AudioCodec::kAAC) {
+    codec_delay = 0;
+  }
+
   config->Initialize(codec, sample_format,
                      {channel_layout, codec_context->ch_layout.nb_channels},
                      codec_context->sample_rate, extra_data, encryption_scheme,
-                     seek_preroll, codec_context->delay);
+                     seek_preroll, codec_delay);
 
 #if BUILDFLAG(ENABLE_PLATFORM_AC3_EAC3_AUDIO)
   // These are bitstream formats unknown to ffmpeg, so they don't have
diff --git a/media/filters/audio_file_reader_unittest.cc b/media/filters/audio_file_reader_unittest.cc
index d138e450..0432e78 100644
--- a/media/filters/audio_file_reader_unittest.cc
+++ b/media/filters/audio_file_reader_unittest.cc
@@ -270,8 +270,8 @@
 
 #if BUILDFLAG(USE_PROPRIETARY_CODECS)
 TEST_P(AudioFileReaderTest, AAC) {
-  RunTest("sfx.m4a", "2.47,2.30,2.45,2.80,3.06,3.56,", 1, 44100,
-          base::Microseconds(347665), 15333, 12719);
+  RunTest("sfx.m4a", "0.79,2.31,4.15,4.92,4.04,1.44,", 1, 44100,
+          base::Microseconds(347665), 15333, 12701);
 }
 
 TEST_P(AudioFileReaderTest, AAC_SinglePacket) {
diff --git a/media/test/pipeline_integration_test.cc b/media/test/pipeline_integration_test.cc
index 03bf168a..66962cc 100644
--- a/media/test/pipeline_integration_test.cc
+++ b/media/test/pipeline_integration_test.cc
@@ -2060,20 +2060,9 @@
   Play();
   ASSERT_TRUE(WaitUntilOnEnded());
 
-  // Verify preroll is stripped. This file uses a preroll of 2112 frames, which
-  // spans all three packets in the file. Postroll is not correctly stripped at
-  // present; see the note below.
-  EXPECT_AUDIO_HASH("3.84,4.25,4.33,3.58,3.27,3.16,");
-
-  // Note the above hash is incorrect since the <audio> path doesn't properly
-  // trim trailing silence at end of stream for AAC decodes. This isn't a huge
-  // deal since plain src= tags can't splice streams and MSE requires an
-  // explicit append window for correctness.
-  //
-  // The WebAudio path via AudioFileReader computes this correctly, so the hash
-  // below is taken from that test.
-  //
-  // EXPECT_AUDIO_HASH("3.77,4.53,4.75,3.48,3.67,3.76,");
+  // Verify preroll and postroll are correctly stripped. This file uses a
+  // preroll of 2112 frames, which spans all three packets in the file.
+  EXPECT_AUDIO_HASH("3.77,4.53,4.75,3.48,3.67,3.76,");
 }
 
 #if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_WIN)
diff --git a/third_party/ffmpeg b/third_party/ffmpeg
index fcf00a6..2b68d2b 160000
--- a/third_party/ffmpeg
+++ b/third_party/ffmpeg
@@ -1 +1 @@
-Subproject commit fcf00a65aa4168c2ae1ce6e55f59e8bc1edd6c78
+Subproject commit 2b68d2babae73714846961fb0ee47e3b3d2e39a9
Loading diff…

Regression Test / PoC

shipped with the fix
diff --git a/media/filters/audio_file_reader_unittest.cc b/media/filters/audio_file_reader_unittest.cc
index d138e450..0432e78 100644
--- a/media/filters/audio_file_reader_unittest.cc
+++ b/media/filters/audio_file_reader_unittest.cc
@@ -270,8 +270,8 @@
 
 #if BUILDFLAG(USE_PROPRIETARY_CODECS)
 TEST_P(AudioFileReaderTest, AAC) {
-  RunTest("sfx.m4a", "2.47,2.30,2.45,2.80,3.06,3.56,", 1, 44100,
-          base::Microseconds(347665), 15333, 12719);
+  RunTest("sfx.m4a", "0.79,2.31,4.15,4.92,4.04,1.44,", 1, 44100,
+          base::Microseconds(347665), 15333, 12701);
 }
 
 TEST_P(AudioFileReaderTest, AAC_SinglePacket) {
diff --git a/media/test/pipeline_integration_test.cc b/media/test/pipeline_integration_test.cc
index 03bf168a..66962cc 100644
--- a/media/test/pipeline_integration_test.cc
+++ b/media/test/pipeline_integration_test.cc
@@ -2060,20 +2060,9 @@
   Play();
   ASSERT_TRUE(WaitUntilOnEnded());
 
-  // Verify preroll is stripped. This file uses a preroll of 2112 frames, which
-  // spans all three packets in the file. Postroll is not correctly stripped at
-  // present; see the note below.
-  EXPECT_AUDIO_HASH("3.84,4.25,4.33,3.58,3.27,3.16,");
-
-  // Note the above hash is incorrect since the <audio> path doesn't properly
-  // trim trailing silence at end of stream for AAC decodes. This isn't a huge
-  // deal since plain src= tags can't splice streams and MSE requires an
-  // explicit append window for correctness.
-  //
-  // The WebAudio path via AudioFileReader computes this correctly, so the hash
-  // below is taken from that test.
-  //
-  // EXPECT_AUDIO_HASH("3.77,4.53,4.75,3.48,3.67,3.76,");
+  // Verify preroll and postroll are correctly stripped. This file uses a
+  // preroll of 2112 frames, which spans all three packets in the file.
+  EXPECT_AUDIO_HASH("3.77,4.53,4.75,3.48,3.67,3.76,");
 }
 
 #if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_WIN)
Loading diff…

Original Bug Report

reported by vm...@google.com

Potential Heap OOB write in FFmpeg FLAC RISC-V Vector kernels via loop underflow

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 Chrome Security team. Please see go/chrome-ai-generated-security-bugs-faq for more information.

Overview: The RISC-V Vector (RVV) FLAC LPC kernels in FFmpeg fail to guard against cases where the number of samples equals the predictor order. This leads to an immediate loop counter underflow and a sequential heap out-of-bounds write in the renderer process. The issue is reachable via standard web audio APIs on supported hardware.

Affected files:

  • third_party/ffmpeg/libavcodec/riscv/flacdsp_rvv.S
  • third_party/ffmpeg/libavcodec/flacdec.c
  • third_party/ffmpeg/libavcodec/riscv/flacdsp_init.c

Estimated timestamp from git blame: 2024-05-27

Description

A potential heap out-of-bounds (OOB) write vulnerability exists in the RISC-V Vector (RVV) implementation of FLAC LPC (Linear Predictive Coding) reconstruction kernels within Chromium’s FFmpeg copy.

In third_party/ffmpeg/libavcodec/riscv/flacdsp_rvv.S, the DSP kernels (e.g., ff_flac_lpc16_rvv) calculate their loop iteration count by subtracting the predictor order (pred_order) from the total length (len). The kernels use a do-while loop structure without an initial guard to ensure len > pred_order. If len == pred_order, the loop counter initializes to 0, immediately underflows to -1 (0xFFFFFFFFFFFFFFFF) inside the loop, and continues for approximately 2^64 iterations, causing a massive sequential OOB read-modify-write across the heap.

Root Cause Analysis

There are two interacting flaws that make this reachable:

  1. Permissive Check in Decoder: In third_party/ffmpeg/libavcodec/flacdec.c, the function decode_residuals verifies the predictor order against the number of samples in a partition: if (pred_order > samples) { ... return AVERROR_INVALIDDATA; } (line 270). This check uses strict inequality. If a crafted frame sets blocksize to 32, pred_order to 32, and rice_order to 0, then samples evaluates to 32. The check passes because 32 is not greater than 32.
  2. Missing Guard in Assembly: The execution proceeds to call the DSP functions (e.g., s->dsp.lpc16) passing s->blocksize (32) as the len argument and 32 as pred_order. In flacdsp_rvv.S (line 23, ff_flac_lpc16_rvv):
            sub     a4, a4, a2          // a4 (counter) = 32 - 32 = 0
            ...
    1:
            // ... loop body ...
            addi    a4, a4, -1          // a4 underflows to -1
            // ... out of bounds memory write occurs here ...
            bnez    a4, 1b              // Branches back because -1 != 0
    
    Unlike the C and x86/ARM assembly implementations which safely skip the loop if len <= pred_order, the RVV implementation falls straight through.

Potential Impact & Exploitability

This is a classic ‘wild copy’ vulnerability occurring in the sandboxed renderer process when processing media via the <audio> tag or WebCodecs. While the enormous loop will inevitably attempt to access an unmapped page and trigger a SIGSEGV, the sequential writing takes measurable CPU time.

An attacker could potentially exploit this by running a concurrent Web Worker. By grooming the heap layout prior to the OOB write, the Web Worker could race the crash window to hijack corrupted Javascript objects or function pointers before the kernel terminates the process, potentially leading to Remote Code Execution (RCE) within the sandbox. Because the corruption occurs in uninstrumented third-party assembly via raw pointers, MiraclePtr (BackupRefPtr) provides no protection.

Potential Reproduction Steps

(Note: These are suggested steps based on static analysis; our tooling agent cannot execute code to verify.)

  1. Use a Chromium build for riscv64 with RVV support enabled (e.g., in QEMU with -cpu rv64,v=true).
  2. Craft a FLAC audio file containing a frame where:
    • blocksize is explicitly set to 32.
    • A subframe is type LPC with a prediction order of 32.
    • The subframe’s residual data uses a rice_order of 0.
  3. Host the file and load it in the renderer using an HTML5 <audio> tag.
  4. The ff_flac_lpc16_rvv function will trigger the massive loop, ultimately causing a renderer crash (SIGSEGV), demonstrating the memory corruption.

Suggested Fix

  1. Assembly Guard: Update the RVV kernels in third_party/ffmpeg/libavcodec/riscv/flacdsp_rvv.S to include a branch instruction before the loop to exit early if the calculated iteration count is zero or negative (e.g., blez a4, end).
  2. Upstream FFmpeg: Ensure this fix is contributed back to upstream FFmpeg.
  3. Decoder Check (Optional but recommended): Re-evaluate the logic in flacdec.c to determine if pred_order == samples is semantically valid for all partitions. If it implies no residuals are present, skipping the DSP call entirely in C might be safer.

Evaluated with Chrome root at commit: 7353d249d9cacf9c7218e1d7b8a39cf39c72d646


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.

View on issue tracker