Chrome · Media
CVE-2026-5909
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 b....@gmail.com
Signed Integer overflow in H264 SEI Parsing
Steps to reproduce the problem
- Build chrome libfuzzer with below mentioned args
- execute the fuzzer with the attached malformed H264 file
- Signed Integer overflow crash detected
Problem Description
A signed integer overflow occurs in chromiums H264 parser while processing SEI. The crash happens when multiplying a large parsed value.
Vulnerable file details
media/parsers/h264_parser.cc
Function : media::H264Parser::ParseSEI(media::H264SEI*)
Line : 1549
Build Args:
gn gen out/ASanMedia --args='
is_asan=true
is_ubsan_security=true
is_debug=false
is_component_build=false
proprietary_codecs=true
ffmpeg_branding="Chrome"
symbol_level=1
use_remoteexec=false
use_libfuzzer=true
mac_sdk_min="26"
angle_enable_metal=false
'
autoninja -C out/ASanMedia media_h264_parser_fuzzer
Execution args
./media_h264_parser_fuzzer h264_sei_overflow.h264
Attached a poc file which contains the crafted sei payload for h264 which results in large parsed value causing the integer overflow
Summary
Signed Integer overflow in H264 SEI Parsing
Custom Questions
Crash state:
Crash state:
INFO: Running with entropic power schedule (0xFF, 100).
INFO: Seed: 4038822869
INFO: Loaded 1 modules (3274258 inline 8-bit counters): 3274258 [0x104c70000, 0x104f8f612),
ASanMedia/media_h264_parser_fuzzer: Running 1 inputs 1 time(s) each.
Running: /h264_sei_overflow.h264
../../media/parsers/h264_parser.cc:1549:40: runtime error: signed integer overflow: 268435456 * 8 cannot be represented in type 'int'
#0 0x0001046f02c4 in media::H264Parser::ParseSEI(media::H264SEI*) media/parsers/h264_parser.cc:1549:40
#1 0x00010457a01c in LLVMFuzzerTestOneInput media/parsers/h264_parser_fuzzertest.cc:65:22
#2 0x0001045b8438 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) third_party/libFuzzer/src/FuzzerLoop.cpp:619:13
#3 0x00010458ca74 in fuzzer::RunOneTest(fuzzer::Fuzzer*, char const*, unsigned long) third_party/libFuzzer/src/FuzzerDriver.cpp:329:6
#4 0x0001045946a0 in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) third_party/libFuzzer/src/FuzzerDriver.cpp:864:9
#5 0x00010457a81c in main third_party/libFuzzer/src/FuzzerMain.cpp:20:10
#6 0x00018486dd50 in start (/usr/lib/dyld:arm64e+0x8d50)
*
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior ../../media/parsers/h264_parser.cc:1549:40
Executed /h264_sei_overflow.h264 in 364 ms
***
*** NOTE: fuzzing was not performed, you have only
*** executed the target code on a fixed set of inputs.
***
Reporter credit:
Mohammed Yasar B & Ameen Basha M K
Additional Data
Category: Security
Chrome Channel: Not sure
Regression: N/A \
References
On This Page