CVE-2026-8535
Overview
Changed Functions
| Function | Change | Notes |
|---|---|---|
ifmedia/parsers/jpeg_parser.cc |
modified |
Files Changed
media/parsers/jpeg_parser.ccmedia/parsers/parse_jpeg.rs
Patch
From 24e44607b2d6dda11f794522fe5d93f5fd09c9b7 Mon Sep 17 00:00:00 2001
From: Eugene Zemtsov <eugene@chromium.org>
Date: Mon, 23 Mar 2026 19:35:02 -0700
Subject: [PATCH] media: Add bounds check for JPEG quantization table selector
The C++ and Rust JPEG parsers previously failed to validate the
`quantization_table_selector` found in the Start of Frame (SOF) marker.
This unvalidated value was passed to hardware decoders like VA-API, which
uses it as an array index, potentially leading to out-of-bounds memory
reads in the GPU process.
This CL adds bounds checking against `kJpegMaxQuantizationTableNum` (4)
in `jpeg_parser.cc` and `parse_jpeg.rs`.
Bug: 495530312
Change-Id: I776b72e44b8ea73c52b80d93c6a9598bc0f800d3
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7693890
Commit-Queue: Jordan Bayles <jophba@chromium.org>
Reviewed-by: Jordan Bayles <jophba@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1603862}
---
diff --git a/media/parsers/jpeg_parser.cc b/media/parsers/jpeg_parser.cc
index 426c922..000267c74 100644
--- a/media/parsers/jpeg_parser.cc
+++ b/media/parsers/jpeg_parser.cc
@@ -192,6 +192,11 @@
return false;
}
READ_U8_OR_RETURN_FALSE(component.quantization_table_selector);
+ if (component.quantization_table_selector >= kJpegMaxQuantizationTableNum) {
+ DVLOG(1) << "Invalid quantization table selector "
+ << static_cast<int>(component.quantization_table_selector);
+ return false;
+ }
}
// The size of data unit is 8*8 and the coded size should be extended
diff --git a/media/parsers/parse_jpeg.rs b/media/parsers/parse_jpeg.rs
index 9013299..5da7be90 100644
--- a/media/parsers/parse_jpeg.rs
+++ b/media/parsers/parse_jpeg.rs
@@ -83,6 +83,7 @@
ExpectedMarkerPrefix = 25,
OnlySof0Supported = 26,
DqtMarkerNotFound = 27,
+ InvalidQuantizationTableSelector = 28,
}
struct JpegParseResult {
@@ -214,6 +215,9 @@
}
let quantization_table_selector = read_u8(&mut cursor)?;
+ if quantization_table_selector as usize >= K_JPEG_MAX_QUANTIZATION_TABLE_NUM {
+ return Err(JpegParserError::InvalidQuantizationTableSelector);
+ }
frame_header.components.push(JpegComponent {
id,
Original Bug Report
Potential OOB Read in VA-API Driver via Unvalidated JPEG Quantization Table Selector
Flapjack (go/flapjack), an LLM-powered static analysis tool, has identified the following potential security issue.
Overview: A compromised renderer process can potentially trigger an out-of-bounds read in the GPU process by supplying a malicious JPEG to the hardware decoder. The JPEG parser fails to validate the quantization table selector, passing an arbitrary index to the VA-API driver. This can leak GPU memory contents back to the renderer through the decoded image.
Affected files:
media/parsers/jpeg_parser.ccmedia/gpu/vaapi/vaapi_jpeg_decoder.cc
Estimated timestamp from git blame: 2024-04-12
This issue allows a compromised renderer to potentially leak GPU process memory via an out-of-bounds read in the VA-API hardware decoder, aiding in a sandbox escape.
Technical Details
Standard Mojo IPC setup from a compromised renderer establishes a MjpegDecodeAccelerator session. The vulnerability occurs during the parsing of the JPEG bitstream.
When parsing the JPEG_SOF0 marker, media/parsers/jpeg_parser.cc reads the quantization_table_selector for each image component but does not enforce the 0-3 baseline limit:
// media/parsers/jpeg_parser.cc : ParseSOF()
READ_U8_OR_RETURN_FALSE(component.quantization_table_selector);
This unvalidated selector (which can be up to 255) is mapped directly to pic_param_components[i].quantiser_table_selector in media/gpu/vaapi/vaapi_jpeg_decoder.cc and passed to the third-party VA-API driver in the GPU process.
The VA-API driver uses this value to index the 4-element quantization table array (e.g., VAIQMatrixBufferJPEGBaseline). Providing an index > 3 results in a direct OOB read. The OOB memory is treated as quantization matrix data, mathematically embedding the leaked memory into the output decoded image pixels.
Potential Attacker Steps
(Note: These are suggested/potential steps, as the Flapjack LLM agent does not have the ability to run code to verify a working exploit).
- Gain code execution in a sandboxed renderer process.
- Bind the
viz::mojom::Gpuinterface and callCreateJpegDecodeAccelerator()to reach the GPU process. - Send a decode request containing a malicious JPEG with the
quantization_table_selectorset to an out-of-bounds value (e.g., 255) in the SOF0 marker. - Read the resulting decoded image buffer and reverse the IDCT/dequantization math to infer the OOB memory contents from the GPU process.
Suggested Fix
Add a bounds check in media/parsers/jpeg_parser.cc within the ParseSOF function to ensure the selector does not exceed the maximum allowed tables:
READ_U8_OR_RETURN_FALSE(component.quantization_table_selector);
if (component.quantization_table_selector >= kJpegMaxQuantizationTableNum) {
DVLOG(1) << "Invalid quantization table selector";
return false;
}
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.