Medium watch ✔︎ verified CVSS 8.3 chrome Integer Overflow 📄 Reporter bug report 🔧 Commit mapped

Overview

Medium
Severity
8.3
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactInteger overflow in Codecs
DescriptionInteger overflow in Codecs
ComponentCodecs
Bug ClassInteger Overflow
Action tierwatch — corruption primitive but gated (uncommon) — not default-reachable — factors set by independent review by AI
Computed by PatchGap's deterministic exploitability ruler from the fixing commit. patch-now = RCE-class & attacker-reachable in a default config, or exploited in the wild; watch = real security signal below that bar; noise = no security relevance.
Independent review by AIConfirmed
A second, independent AI reviewer (not a human) re-derived this analysis from the fixing commit and the vendor advisory, looking for errors.
Tracker495417883
Fix commit42ff1bc25559 (chromium/src) +7/-0
CWECWE-472
CVSS vectorCVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:C/C:H/I:H/A:H
CISA KEVNot listed
CreditedGoogle
Reported2026-03-23 (per vendor advisory)
Fix landed2026-03-25 (public git)
Disclosed2026-05-12
Patch gap48 days — fix public in source before the advisory

Background

`Vp8Parser`
Chromium’s VP8 bitstream parser in media/parsers/vp8_parser.cc.
`first_part_size`
a field from the VP8 uncompressed frame tag giving the byte size of the first (control) partition.
`Vp8BoolDecoder` / `bd_`
the boolean entropy decoder whose BitOffset() reports how many bits of the compressed header were consumed.
`macroblock_bit_offset`
the stored bit position after the compressed header, later used by hardware delegates to derive the first-partition data size.

Root Cause Analysis

In the pre-fix Vp8Parser::ParseFrameHeader, after parsing the compressed header the parser unconditionally recorded fhdr->macroblock_bit_offset = bd_.BitOffset() at media/parsers/vp8_parser.cc:231 and returned success at :236. It never checked that the number of header bytes actually consumed, (bd_.BitOffset() + 7) / 8, fit within the attacker-declared first_part_size. The advisory notes that downstream hardware delegates compute the first-partition macroblock data size as first_part_size - ((macroblock_bit_offset + 7) / 8); when the consumed header size exceeds a tiny first_part_size, that unsigned subtraction underflows to a near-UINT_MAX value (those delegate files are named by the reporter but are not part of the shown diff).

The fix adds, immediately before :231, the guard if (fhdr->first_part_size < (bd_.BitOffset() + 7) / 8) { ... return false; }, rejecting any frame whose compressed header does not fit inside first_part_size. This tightens parsing so the invariant “consumed header size ≤ first_part_size” holds before macroblock_bit_offset is stored, making the later subtraction unable to underflow.

Key insight
The parser never verified that the consumed compressed-header size fits within first_part_size, allowing a later unsigned subtraction to underflow; the fix adds that bound check in ParseFrameHeader and fails the frame.

Attack Path

  1. Craft a tiny `first_part_size` A VP8 keyframe tag declares a very small first_part_size.
  2. Emit a larger header The compressed header consumes more bytes than first_part_size, which pre-fix ParseFrameHeader accepted without complaint (vp8_parser.cc:231).
  3. Underflow downstream A hardware delegate subtracts the header size from first_part_size, wrapping to a huge unsigned partition size. (inferred — the subtraction site is not in the shown diff.)
  4. Out-of-bounds hardware access The oversized size is handed to the GPU driver/hardware, which the advisory links to out-of-bounds memory access. (inferred.)

Impact Assessment

The advisory records an integer overflow in Codecs, medium severity, not in the wild. On VA-API/V4L2 hardware VP8 decode an underflowed partition size could be passed to the GPU driver or kernel, which the reporter links to out-of-bounds reads/writes and potential GPU-process or kernel memory corruption; that escalation is (inferred) and not shown in the parser source.

Files Changed

  • media/parsers/vp8_parser.cc

Audit Directions

  • Unvalidated declared sizes
    When a bitstream declares a sub-buffer size (like first_part_size), verify that consumed bytes fit before any code subtracts them.
  • Unsigned subtraction underflow
    Audit A - B on unsigned types where B is derived from parsed/consumed data and can exceed A, wrapping to a near-UINT_MAX value.
From 42ff1bc2555928f16a43ec23f4f66f28e0976460 Mon Sep 17 00:00:00 2001
From: Ted Meyer <tmathmeyer@chromium.org>
Date: Tue, 24 Mar 2026 18:59:03 -0700
Subject: [PATCH] Add bounds checking to VP8 Accelerator

Previously, an unchecked subtraction between two bitstream values
`first_part_size` and `macroblock_bit_offset` was calculated and sent to
hardware decoders. This change adds validation prevent unsigned int
underflow.

Fixed: 495417883
Change-Id: I348afd828394e68a0796037a46cbee3c129eaefd
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7698802
Commit-Queue: Ted (Chromium) Meyer <tmathmeyer@chromium.org>
Reviewed-by: Eugene Zemtsov <eugene@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1604550}
---

diff --git a/media/parsers/vp8_parser.cc b/media/parsers/vp8_parser.cc
index f178604a..ed7c04d2 100644
--- a/media/parsers/vp8_parser.cc
+++ b/media/parsers/vp8_parser.cc
@@ -228,6 +228,13 @@
       return false;
   }
 
+  if (fhdr->first_part_size < (bd_.BitOffset() + 7) / 8) {
+    // If a video is created in such a way that the `first_part_size` field in
+    // the bitstream is smaller than the macroblock_bit_offset/8, the frame is
+    // not valid. Calculating the partition size becomes impossible.
+    return false;
+  }
+
   fhdr->macroblock_bit_offset = bd_.BitOffset();
   fhdr->bool_dec_range = bd_.GetRange();
   fhdr->bool_dec_value = bd_.GetBottom();
Loading diff…

Original Bug Report

reported by rj...@google.com

Potential integer underflow in VP8 parser leads to GPU OOB read/write

Flapjack (go/flapjack), an LLM-powered static analysis tool, has identified the following potential security issue.

Overview: The Vp8Parser fails to validate that the size of the compressed frame header does not exceed the first_part_size declared in the VP8 frame tag. This causes an integer underflow when calculating the control partition size for VA-API and V4L2 hardware decoders. The massive underflowed size is passed to GPU drivers and potentially the kernel, leading to out-of-bounds memory access, information leaks, or GPU process RCE.

Affected files:

  • media/parsers/vp8_parser.cc
  • media/gpu/vaapi/vaapi_utils.cc
  • media/gpu/v4l2/v4l2_video_decoder_delegate_vp8.cc
  • media/gpu/vaapi/test/vp8_decoder.cc

Estimated timestamp from git blame: 2021-11-09

Summary

A potential integer underflow leading to an out-of-bounds read/write was identified in Chromium’s VP8 video decoding utility. The root cause is a lack of validation in media::Vp8Parser::ParseFrameHeader (media/parsers/vp8_parser.cc), which fails to ensure that the number of bits consumed when reading the compressed frame header does not exceed the first_part_size specified in the uncompressed VP8 frame tag.

Technical Details

  1. Parsing Frame Tag: In media/parsers/vp8_parser.cc, the Vp8Parser::ParseFrameTag method extracts the first_part_size from the VP8 frame tag (a 19-bit value). An attacker can craft a frame tag where this value is arbitrarily small (e.g., 5).
  2. Parsing Compressed Header: Subsequently, Vp8Parser::ParseFrameHeader uses a Vp8BoolDecoder to parse the compressed header. Crucially, the decoder is initialized with the entire remaining frame buffer (bytes_left_), not just the first_part_size bytes. The number of bits consumed during this process is stored in fhdr->macroblock_bit_offset.
  3. Missing Validation: The parser successfully returns without verifying that the bytes consumed for the compressed header ((macroblock_bit_offset + 7) / 8) actually fit within the first_part_size.
  4. The Underflow: In multiple hardware video decoder delegates, such as media/gpu/vaapi/vaapi_utils.cc (and similarly in media/gpu/vaapi/test/vp8_decoder.cc), the size of the first partition’s macroblock data is calculated by subtracting the header size from first_part_size:
    slice_param->partition_size[0] =
        frame_header.first_part_size -
        ((frame_header.macroblock_bit_offset + 7) / 8);
    
    If the attacker-controlled first_part_size (e.g., 5) is smaller than the consumed header size in bytes (e.g., 13), an unsigned integer underflow occurs. Since partition_size[0] is an unsigned 32-bit integer (uint32_t in the VA-API VASliceParameterBufferVP8 struct), it wraps around to an extremely large value (e.g., 0xFFFFFFF8).

Impact

  • GPU Information Leak / ASLR Bypass: This massive size is passed directly to the VA-API hardware/driver via vaapi_wrapper_->MapAndCopyAndExecute in the privileged GPU process. The hardware may read massively beyond the end of the provided bitstream buffer. If the driver or hardware interprets this out-of-bounds data as macroblock data and incorporates it into the decoded frame, a cross-origin attacker could render the video to a canvas, extract the pixels, and read arbitrary GPU memory contents.
  • Remote Code Execution (RCE): If the specific VA-API driver implementation (e.g., Intel media driver, Mesa) performs internal buffer allocations or memory copies (memcpy) based on this massive partition size before hardware submission, it will result in a heap buffer overflow and arbitrary code execution within the GPU process.
  • Potential Kernel Sandbox Escape: On V4L2-based platforms (e.g., ChromeOS on ARM), these unvalidated values are copied into a v4l2_ctrl_vp8_frame structure and passed directly to the kernel via ioctl in media/gpu/v4l2/v4l2_video_decoder_delegate_vp8.cc. If the kernel driver performs the same subtraction without underflow validation, it could result in a kernel-level out-of-bounds read/write and a full sandbox escape.

Potential Steps to Reproduce

Note: These are potential steps as a full Proof of Concept (PoC) has not yet been executed.

  1. Craft a WebM media file containing a VP8 video track.
  2. Modify a single VP8 keyframe in the bitstream.
  3. Set the first_part_size field in the uncompressed frame tag to a very small value (e.g., 5).
  4. Ensure the subsequent compressed frame header contains valid boolean entropy data that consumes more bytes than the first_part_size (e.g., > 40 bits).
  5. Serve this malicious WebM file via an HTML5 <video> element on an attacker-controlled webpage.
  6. When the victim visits the page on a device supporting VA-API or V4L2 hardware decoding, the Chromium media pipeline will parse the frame without error and pass the underflowed size to the GPU driver/kernel.

Evaluated with Chrome root at commit: 9760e6c70cd33a320713361f17c6dcca85648c0f


Results from Flapjack so far have been promising, but it can be wrong in its deductions. At this time, it does not produce proof of concepts or fuzzer tests. If this proves to be a false positive, please close as WAI; data from false positives will be used to improve Flapjack’s 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