Chrome · Media
CVE-2026-5908
Integer Overflow in Media
Overview
Low
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
Changed Functions
| Function | Change | Notes |
|---|---|---|
whilemedia/parsers/h264_parser.cc |
modified | |
ifmedia/parsers/h265_parser.cc |
modified | |
whilemedia/parsers/h265_parser.cc |
modified |
Files Changed
media/parsers/h264_parser.ccmedia/parsers/h265_parser.cc
Patch
From 7cf2bae3b0688de45d5215e768ca987f2967fc46 Mon Sep 17 00:00:00 2001
From: Eugene Zemtsov <eugene@chromium.org>
Date: Wed, 18 Feb 2026 14:30:58 -0800
Subject: [PATCH] media: Fix integer overflows in H264 and H265 parsers
This change addresses multiple integer overflow issues in the
H.264 and H.265 bitstream parsers.
The following calculations are now protected or validated:
- H.264/H.265 `ParseSEI`: The accumulation of SEI message `type` and
`payload_size` is now protected using `base::CheckedNumeric`.
- H.265 `ParseSliceHeader`:
- The summation of `delta_poc_msb_cycle_lt` values is now protected
using `base::CheckedNumeric`.
- `slice_qp_delta` validation is refactored to check the delta against
derived bounds instead of performing a potentially overflowing addition.
- `num_entry_point_offsets` upper bound calculation and the subsequent
bit skip calculation are now protected using `base::CheckedNumeric`.
- H.265 `ParsePredWeightTable`:
- `delta_chroma_log2_weight_denom` is now validated against constant
bounds [-7, 7] before addition to prevent signed integer overflow.
Bug: 485203821, 485115554, 485212874
Change-Id: Ifc8da5426b0d9f0e3bbfed30d175e62af46bca22
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7586436
Reviewed-by: Ted (Chromium) Meyer <tmathmeyer@chromium.org>
Commit-Queue: Eugene Zemtsov <eugene@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1586702}
---
diff --git a/media/parsers/h264_parser.cc b/media/parsers/h264_parser.cc
index d0814220..03cafeb3 100644
--- a/media/parsers/h264_parser.cc
+++ b/media/parsers/h264_parser.cc
@@ -1542,22 +1542,43 @@
// the parsed SEI messages, so we have to set a limit here.
constexpr int kMaxParsedSEIMessages = 64;
do {
- int type = 0;
+ base::CheckedNumeric<int> type_checked = 0;
READ_BITS_OR_RETURN(8, &byte);
while (byte == 0xff) {
- type += 255;
+ type_checked += 255;
READ_BITS_OR_RETURN(8, &byte);
}
- type += byte;
+ type_checked += byte;
- int payload_size = 0;
+ if (!type_checked.IsValid()) {
+ DVLOG(1) << "SEI type overflow";
+ return kInvalidStream;
+ }
+ int type = type_checked.ValueOrDie();
+
+ base::CheckedNumeric<int> payload_size_checked = 0;
READ_BITS_OR_RETURN(8, &byte);
while (byte == 0xff) {
- payload_size += 255;
+ payload_size_checked += 255;
READ_BITS_OR_RETURN(8, &byte);
}
- payload_size += byte;
- int num_bits_remain = payload_size * 8;
+ payload_size_checked += byte;
+
+ if (!payload_size_checked.IsValid()) {
+ DVLOG(1) << "SEI payload size overflow";
+ return kInvalidStream;
+ }
+
+ int payload_size = payload_size_checked.ValueOrDie();
+ base::CheckedNumeric<int> num_bits_remain_checked =
+ payload_size_checked * 8;
+
+ if (!num_bits_remain_checked.IsValid()) {
+ DVLOG(1) << "SEI payload bits overflow";
+ return kInvalidStream;
+ }
+
+ int num_bits_remain = num_bits_remain_checked.ValueOrDie();
DVLOG(4) << "Found SEI message type: " << type
<< " payload size: " << payload_size;
diff --git a/media/parsers/h265_parser.cc b/media/parsers/h265_parser.cc
index cd4800e9..06303f8 100644
--- a/media/parsers/h265_parser.cc
+++ b/media/parsers/h265_parser.cc
@@ -13,6 +13,7 @@
#include "base/bits.h"
#include "base/logging.h"
#include "base/notreached.h"
+#include "base/numerics/checked_math.h"
#include "base/numerics/safe_conversions.h"
#include "media/base/decrypt_config.h"
#include "media/base/video_codecs.h"
@@ -1272,9 +1273,11 @@
std::pow(2, 32 - sps->log2_max_pic_order_cnt_lsb_minus4 - 4));
// Equation 7-52.
if (i != 0 && i != shdr->num_long_term_sps) {
- shdr->delta_poc_msb_cycle_lt[i] =
- shdr->delta_poc_msb_cycle_lt[i] +
- shdr->delta_poc_msb_cycle_lt[i - 1];
+ base::CheckedNumeric<int> sum = shdr->delta_poc_msb_cycle_lt[i];
+ sum += shdr->delta_poc_msb_cycle_lt[i - 1];
+ if (!sum.AssignIfValid(&shdr->delta_poc_msb_cycle_lt[i])) {
+ return kInvalidStream;
+ }
}
}
}
@@ -1361,8 +1364,9 @@
IN_RANGE_OR_RETURN(5 - shdr->five_minus_max_num_merge_cand, 1, 5);
}
READ_SE_OR_RETURN(&shdr->slice_qp_delta);
- IN_RANGE_OR_RETURN(26 + pps->init_qp_minus26 + shdr->slice_qp_delta,
- -pps->qp_bd_offset_y, 51);
+ int base_qp = 26 + pps->init_qp_minus26;
+ IN_RANGE_OR_RETURN(shdr->slice_qp_delta, -pps->qp_bd_offset_y - base_qp,
+ 51 - base_qp);
if (pps->pps_slice_chroma_qp_offsets_present_flag) {
READ_SE_OR_RETURN(&shdr->slice_cb_qp_offset);
@@ -1410,15 +1414,26 @@
(pps->num_tile_columns_minus1 + 1) * (pps->num_tile_rows_minus1 + 1) -
1);
} else { // both are true
- IN_RANGE_OR_RETURN(
- num_entry_point_offsets, 0,
- (pps->num_tile_columns_minus1 + 1) * sps->pic_height_in_ctbs_y - 1);
+ base::CheckedNumeric<int> limit = pps->num_tile_columns_minus1 + 1;
+ limit *= sps->pic_height_in_ctbs_y;
+ limit -= 1;
+ if (!limit.IsValid()) {
+ return kInvalidStream;
+ }
+ int limit_val = limit.ValueOrDie();
+ IN_RANGE_OR_RETURN(num_entry_point_offsets, 0, limit_val);
}
if (num_entry_point_offsets > 0) {
int offset_len_minus1;
READ_UE_OR_RETURN(&offset_len_minus1);
IN_RANGE_OR_RETURN(offset_len_minus1, 0, 31);
- SKIP_BITS_OR_RETURN(num_entry_point_offsets * (offset_len_minus1 + 1));
+ base::CheckedNumeric<int> bits_to_skip = offset_len_minus1 + 1;
+ bits_to_skip *= num_entry_point_offsets;
+ if (!bits_to_skip.IsValid()) {
+ return kInvalidStream;
+ }
+ int bits_to_skip_val = bits_to_skip.ValueOrDie();
+ SKIP_BITS_OR_RETURN(bits_to_skip_val);
}
}
@@ -2022,6 +2037,8 @@
IN_RANGE_OR_RETURN(pred_weight_table->luma_log2_weight_denom, 0, 7);
if (sps.chroma_array_type) {
READ_SE_OR_RETURN(&pred_weight_table->delta_chroma_log2_weight_denom);
+ IN_RANGE_OR_RETURN(pred_weight_table->delta_chroma_log2_weight_denom, -7,
+ 7);
pred_weight_table->chroma_log2_weight_denom =
pred_weight_table->delta_chroma_log2_weight_denom +
pred_weight_table->luma_log2_weight_denom;
@@ -2117,22 +2134,43 @@
// the parsed SEI messages, so we have to set a limit here.
constexpr int kMaxParsedSEIMessages = 64;
do {
- int type = 0;
+ base::CheckedNumeric<int> type_checked = 0;
READ_BITS_OR_RETURN(8, &byte);
while (byte == 0xff) {
- type += 255;
+ type_checked += 255;
READ_BITS_OR_RETURN(8, &byte);
}
- type += byte;
+ type_checked += byte;
- int payload_size = 0;
+ if (!type_checked.IsValid()) {
+ DVLOG(1) << "SEI type overflow";
+ return kInvalidStream;
+ }
+ int type = type_checked.ValueOrDie();
+
+ base::CheckedNumeric<int> payload_size_checked = 0;
READ_BITS_OR_RETURN(8, &byte);
while (byte == 0xff) {
- payload_size += 255;
+ payload_size_checked += 255;
READ_BITS_OR_RETURN(8, &byte);
}
- payload_size += byte;
- int num_bits_remain = payload_size * 8;
+ payload_size_checked += byte;
+
+ if (!payload_size_checked.IsValid()) {
+ DVLOG(1) << "SEI payload size overflow";
+ return kInvalidStream;
Loading diff…
Original Bug Report
reported by am...@gmail.com
Integer Overflow in H265 SEI Parsing
Steps to reproduce the problem
- Build Chrome libfuzzer with below mentioned args
- execute the fuzzer with attached malformed H265 file
- Integer Overflow Crash Detected
Problem Description
A signed integer overflow occurs in Chromium’s H.265 parser while processing SEI (Supplemental Enhancement Information) data. The overflow happens during multiplication of a large parsed value, which can lead to crash
Vulnerable File Details
media/parsers/h265_parser.cc
Function: media::H265Parser::ParseSEI
Line: 2144
Build Args:
gn gen out/Media --args='
is_asan=true
is_debug=false
is_ubsan_security=true
is_component_build=false
proprietary_codecs=true
ffmpeg_branding="Chrome"
symbol_level=1
use_remoteexec=false
use_libfuzzer=true
angle_enable_metal=false
'
autoninja -C out/Media media_h265_parser_fuzzer
Execution Args:
./media_h265_parser_fuzzer sei_overflow.h265
Attached a poc file, The file contains a crafted SEI payload with a large parsed field value designed to overflow during size calculation.
Summary
Integer Overflow in H265 SEI Parsing
Custom Questions
Crash state:
INFO: Running with entropic power schedule (0xFF, 100).
INFO: Seed: 4166765090
INFO: Loaded 1 modules (2164628 inline 8-bit counters): 2164628 [0x630b9b2a4ac0, 0x630b9b4b5254),
INFO: Loaded 1 PC tables (2164628 PCs): 2164628 [0x630b9b4b5258,0x630b9d5bcb98),
./media_h265_parser_fuzzer: Running 1 inputs 1 time(s) each.
Running: /home/basha/Downloads/win_repro/sei_overflow.h265
../../media/parsers/h265_parser.cc:2144:40: runtime error: signed integer overflow: 268435456 * 8 cannot be represented in type 'int'
#0 0x630b922e623c in media::H265Parser::ParseSEI(media::H265SEI*) media/parsers/h265_parser.cc:2144:40
#1 0x630b8e0677b7 in LLVMFuzzerTestOneInput media/parsers/h265_parser_fuzzertest.cc:43:22
#2 0x630b8e0ab27c in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) third_party/libFuzzer/src/FuzzerLoop.cpp:619:13
#3 0x630b8e07c2b1 in fuzzer::RunOneTest(fuzzer::Fuzzer*, char const*, unsigned long) third_party/libFuzzer/src/FuzzerDriver.cpp:328:6
#4 0x630b8e084da0 in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) third_party/libFuzzer/src/FuzzerDriver.cpp:863:9
#5 0x630b8e067fdd in main third_party/libFuzzer/src/FuzzerMain.cpp:20:10
#6 0x7ef19742a1c9 in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16
#7 0x7ef19742a28a in __libc_start_main csu/../csu/libc-start.c:360:3
#8 0x630b8df8ab29 in _start (/home/basha/Desktop/chromefuzz/chromium/src/out/UBSanMedia/media_h265_parser_fuzzer+0x7c11b29) (BuildId: 851ee95e8c3708a1)
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior ../../media/parsers/h265_parser.cc:2144:40
Executed /home/basha/Downloads/win_repro/sei_overflow.h265 in 275 ms
***
*** NOTE: fuzzing was not performed, you have only
*** executed the target code on a fixed set of inputs.
***
Reporter credit:
Ameen Basha M K & Mohammed Yasar B
Additional Data
Category: Security
Chrome Channel: Not sure
Regression: N/A \
References
On This Page