From 65df24e6bc5dcea1fdcef4492b184d5c531cdd75 Mon Sep 17 00:00:00 2001 From: Abhijeet Kumar <75058019+NexionisJake@users.noreply.github.com> Date: Sat, 4 Apr 2026 08:34:24 +0530 Subject: [PATCH] Fix integer overflow in ccxr_process_cc_data(): cast cc_count to usize before multiply (#2241) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit cc_count * 3 used i32 arithmetic with no upper-bound check. For cc_count > i32::MAX / 3 (~715 million), debug builds panic on overflow detection and release builds silently wrap around to a negative range, discarding all CC data for the frame. Both are triggerable from malformed media files. Fix: 1. Cast cc_count to usize immediately after the existing <= 0 guard, before any arithmetic — eliminates the overflow entirely 2. Add MAX_CC_COUNT = 31 upper-bound guard — CEA-708/ATSC A/53 encodes cc_count in a 5-bit bitstream field (0x1F mask in avc_functions.c:514), making 31 the spec-defined per-frame maximum; this value is also independently documented in es/userdata.rs ("Maximum cc_count is 31"). Returns -1 with a warn!() log for out-of-range values, consistent with existing error-handling style in the function. 3. Remove the now-redundant `x as usize` cast in the map closure since the range is already usize..usize Fixes #2234 --- src/rust/src/lib.rs | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/rust/src/lib.rs b/src/rust/src/lib.rs index 3801b11a..10a05290 100644 --- a/src/rust/src/lib.rs +++ b/src/rust/src/lib.rs @@ -403,6 +403,19 @@ extern "C" fn ccxr_process_cc_data( return -1; } + // Cast to usize before any arithmetic to prevent i32 overflow. + // CEA-708/ATSC A/53 encodes cc_count in a 5-bit field (max 31); 31 is + // also the value used in es/userdata.rs. Reject anything beyond that. + const MAX_CC_COUNT: usize = 31; + let cc_count_usize = cc_count as usize; + if cc_count_usize > MAX_CC_COUNT { + warn!( + "ccxr_process_cc_data: cc_count {} exceeds maximum {}, discarding frame", + cc_count_usize, MAX_CC_COUNT + ); + return -1; + } + let dec_ctx = unsafe { &mut *dec_ctx }; // Check dtvcc_rust pointer before dereferencing (not dtvcc!) @@ -412,8 +425,8 @@ extern "C" fn ccxr_process_cc_data( } let mut ret = -1; - let mut cc_data: Vec = (0..cc_count * 3) - .map(|x| unsafe { *data.add(x as usize) }) + let mut cc_data: Vec = (0..cc_count_usize * 3) + .map(|x| unsafe { *data.add(x) }) .collect(); // Use the persistent DtvccRust context from dtvcc_rust