From 811d78729d365b428d10895b723d5f72988afc52 Mon Sep 17 00:00:00 2001 From: justinjohn0306 <34035011+justinjohn0306@users.noreply.github.com> Date: Fri, 23 Oct 2026 15:55:15 +0530 Subject: [PATCH] Prevent H264 skip-run bounds overflow --- crates/video/src/h264/slicedec.rs | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/crates/video/src/h264/slicedec.rs b/crates/video/src/h264/slicedec.rs index a71a6b4e..34ae0f14 100644 --- a/crates/video/src/h264/slicedec.rs +++ b/crates/video/src/h264/slicedec.rs @@ -13,6 +13,10 @@ use crate::h264::slice::{SliceHeader, SliceType}; use crate::h264::tables::*; use crate::h264::transform::{self, LevelScale}; +fn skip_run_fits(addr: usize, run: usize, total: usize) -> bool { + addr < total && run <= total - addr +} + /// Per-slice data kept with the picture (deblocking, motion field export). #[derive(Clone, Debug, Default)] pub struct SliceInfo { @@ -1444,7 +1448,7 @@ impl<'a> SliceDecoder<'a> { ensure!(addr < total, "macroblock address {addr} out of range"); if !intra_slice { let run = r.read_ue()? as usize; - ensure!(addr + run <= total, "mb_skip_run out of range"); + ensure!(skip_run_fits(addr, run, total), "mb_skip_run out of range"); for _ in 0..run { self.start_mb(addr); self.decode_skip()?; @@ -1467,3 +1471,16 @@ impl<'a> SliceDecoder<'a> { Ok(()) } } + +#[cfg(test)] +mod tests { + use super::skip_run_fits; + + #[test] + fn skip_run_must_fit_remaining_macroblocks_without_overflow() { + assert!(skip_run_fits(1, 98, 99)); + assert!(!skip_run_fits(1, 99, 99)); + assert!(!skip_run_fits(1, usize::MAX, 99)); + assert!(!skip_run_fits(99, 0, 99)); + } +}