CVE-2026-8573
Overview
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.
first_part_size, allowing a later unsigned subtraction to underflow; the fix adds that bound check in ParseFrameHeader and fails the frame.Attack Path
- Craft a tiny `first_part_size`
A VP8 keyframe tag declares a very small
first_part_size. - Emit a larger header
The compressed header consumes more bytes than
first_part_size, which pre-fixParseFrameHeaderaccepted without complaint (vp8_parser.cc:231). - 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.) - 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
Files Changed
media/parsers/vp8_parser.cc
Audit Directions
- Unvalidated declared sizesWhen a bitstream declares a sub-buffer size (like
first_part_size), verify that consumed bytes fit before any code subtracts them. - Unsigned subtraction underflowAudit
A - Bon unsigned types whereBis derived from parsed/consumed data and can exceedA, wrapping to a near-UINT_MAXvalue.
Patch
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();
Original Bug Report
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.ccmedia/gpu/vaapi/vaapi_utils.ccmedia/gpu/v4l2/v4l2_video_decoder_delegate_vp8.ccmedia/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
- Parsing Frame Tag: In
media/parsers/vp8_parser.cc, theVp8Parser::ParseFrameTagmethod extracts thefirst_part_sizefrom the VP8 frame tag (a 19-bit value). An attacker can craft a frame tag where this value is arbitrarily small (e.g.,5). - Parsing Compressed Header: Subsequently,
Vp8Parser::ParseFrameHeaderuses aVp8BoolDecoderto parse the compressed header. Crucially, the decoder is initialized with the entire remaining frame buffer (bytes_left_), not just thefirst_part_sizebytes. The number of bits consumed during this process is stored infhdr->macroblock_bit_offset. - Missing Validation: The parser successfully returns without verifying that the bytes consumed for the compressed header (
(macroblock_bit_offset + 7) / 8) actually fit within thefirst_part_size. - The Underflow: In multiple hardware video decoder delegates, such as
media/gpu/vaapi/vaapi_utils.cc(and similarly inmedia/gpu/vaapi/test/vp8_decoder.cc), the size of the first partition’s macroblock data is calculated by subtracting the header size fromfirst_part_size:If the attacker-controlledslice_param->partition_size[0] = frame_header.first_part_size - ((frame_header.macroblock_bit_offset + 7) / 8);first_part_size(e.g.,5) is smaller than the consumed header size in bytes (e.g.,13), an unsigned integer underflow occurs. Sincepartition_size[0]is an unsigned 32-bit integer (uint32_tin the VA-APIVASliceParameterBufferVP8struct), 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_->MapAndCopyAndExecutein 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_framestructure and passed directly to the kernel viaioctlinmedia/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.
- Craft a WebM media file containing a VP8 video track.
- Modify a single VP8 keyframe in the bitstream.
- Set the
first_part_sizefield in the uncompressed frame tag to a very small value (e.g.,5). - Ensure the subsequent compressed frame header contains valid boolean entropy data that consumes more bytes than the
first_part_size(e.g., > 40 bits). - Serve this malicious WebM file via an HTML5
<video>element on an attacker-controlled webpage. - 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.