CVE-2026-79231
Overview
Fix not yet public
Original Bug Report
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.Sthird_party/ffmpeg/libavcodec/flacdec.cthird_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:
- Permissive Check in Decoder: In
third_party/ffmpeg/libavcodec/flacdec.c, the functiondecode_residualsverifies 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 setsblocksizeto 32,pred_orderto 32, andrice_orderto 0, thensamplesevaluates to 32. The check passes because 32 is not greater than 32. - Missing Guard in Assembly: The execution proceeds to call the DSP functions (e.g.,
s->dsp.lpc16) passings->blocksize(32) as thelenargument and 32 aspred_order. Inflacdsp_rvv.S(line 23,ff_flac_lpc16_rvv):Unlike the C and x86/ARM assembly implementations which safely skip the loop ifsub 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 != 0len <= 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.)
- Use a Chromium build for
riscv64with RVV support enabled (e.g., in QEMU with-cpu rv64,v=true). - Craft a FLAC audio file containing a frame where:
blocksizeis explicitly set to 32.- A subframe is type LPC with a prediction order of 32.
- The subframe’s residual data uses a
rice_orderof 0.
- Host the file and load it in the renderer using an HTML5
<audio>tag. - The
ff_flac_lpc16_rvvfunction will trigger the massive loop, ultimately causing a renderer crash (SIGSEGV), demonstrating the memory corruption.
Suggested Fix
- Assembly Guard: Update the RVV kernels in
third_party/ffmpeg/libavcodec/riscv/flacdsp_rvv.Sto include a branch instruction before the loop to exit early if the calculated iteration count is zero or negative (e.g.,blez a4, end). - Upstream FFmpeg: Ensure this fix is contributed back to upstream FFmpeg.
- Decoder Check (Optional but recommended): Re-evaluate the logic in
flacdec.cto determine ifpred_order == samplesis 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.