PR #24912 opened by michaelni URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/24912 Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/24912.patch
The picture level slice index accumulated in sh_slice_address() and in the CBS slice header parser (num_entry_points derivation) is used to index the VVC_MAX_SLICES-sized PPS arrays without a range check. When the current subpicture holds no slice top-left corner, the accumulated index can reach pps_num_slices_in_pic_minus1 + 1 and read one entry past slice_start_offset[] / num_ctus_in_slice[] and, in the parser, past pps_slice_width_in_tiles_minus1[] / slice_height_in_ctus[], aliasing unrelated struct fields. The aliased values then inflate num_entry_points beyond the number of entry points the decoder-side walk of the same slice produces, so slice_init_entry_points() consumes entry_point_start_ctu[] entries that were never refreshed for the current picture. On a picture smaller than an earlier one the stale values exceed num_ctus_in_curr_slice, and the entry point walks in slice_init_entry_points() and ff_vvc_frame_submit() read ctb_addr_in_curr_slice[] past the end of the ctb_addr_in_slice allocation. The values read out of bounds then index fc->tab.slice_idx[] out of bounds. Fixes: out of array access Fixes: heap-buffer-overflow Found-by: Umar Pathan (Umar0x) Signed-off-by: Umar Pathan <[email protected]> Fixes: ccSUzeWGhBGj Out of array read Replicated through UnModified FFmpeg with ASAN,UBSAN >From f1c15bee9855239957517af139a6f6d9868463ab Mon Sep 17 00:00:00 2001 From: Umar Pathan <[email protected]> Date: Tue, 29 Sep 2026 16:43:13 +0000 Subject: [PATCH 1/3] lavc/vvc: Validate the slice address against the PPS slice count The picture level slice index accumulated in sh_slice_address() and in the CBS slice header parser (num_entry_points derivation) is used to index the VVC_MAX_SLICES-sized PPS arrays without a range check. When the current subpicture holds no slice top-left corner, the accumulated index can reach pps_num_slices_in_pic_minus1 + 1 and read one entry past slice_start_offset[] / num_ctus_in_slice[] and, in the parser, past pps_slice_width_in_tiles_minus1[] / slice_height_in_ctus[], aliasing unrelated struct fields. The aliased values then inflate num_entry_points beyond the number of entry points the decoder-side walk of the same slice produces, so slice_init_entry_points() consumes entry_point_start_ctu[] entries that were never refreshed for the current picture. On a picture smaller than an earlier one the stale values exceed num_ctus_in_curr_slice, and the entry point walks in slice_init_entry_points() and ff_vvc_frame_submit() read ctb_addr_in_curr_slice[] past the end of the ctb_addr_in_slice allocation. The values read out of bounds then index fc->tab.slice_idx[] out of bounds. Fixes: out of array access Fixes: heap-buffer-overflow Found-by: Umar Pathan (Umar0x) Signed-off-by: Umar Pathan <[email protected]> Fixes: ccSUzeWGhBGj Out of array read Replicated through UnModified FFmpeg with ASAN,UBSAN --- libavcodec/cbs_h266_syntax_template.c | 4 ++++ libavcodec/vvc/ps.c | 2 ++ 2 files changed, 6 insertions(+) diff --git a/libavcodec/cbs_h266_syntax_template.c b/libavcodec/cbs_h266_syntax_template.c index 55178db1ea..6ad4039e1a 100644 --- a/libavcodec/cbs_h266_syntax_template.c +++ b/libavcodec/cbs_h266_syntax_template.c @@ -3462,6 +3462,10 @@ static int FUNC(slice_header) (CodedBitstreamContext *ctx, RWContext *rw, for (i = 0; i < current->curr_subpic_idx; i++) { slice_idx += pps->num_slices_in_subpic[i]; } + if (slice_idx > pps->pps_num_slices_in_pic_minus1) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid slice address %d\n", slice_idx); + return AVERROR_INVALIDDATA; + } if (pps->pps_single_slice_per_subpic_flag) { int width_in_ctus, height_in_ctus; diff --git a/libavcodec/vvc/ps.c b/libavcodec/vvc/ps.c index 2a46680adb..4aa1f4767a 100644 --- a/libavcodec/vvc/ps.c +++ b/libavcodec/vvc/ps.c @@ -1374,6 +1374,8 @@ static int sh_slice_address(VVCSH *sh, const H266RawSPS *sps, const VVCPPS *pps) int pic_level_slice_idx = slice_address; for (int j = 0; j < sh->r->curr_subpic_idx; j++) pic_level_slice_idx += pps->r->num_slices_in_subpic[j]; + if (pic_level_slice_idx > pps->r->pps_num_slices_in_pic_minus1) + return AVERROR_INVALIDDATA; sh->ctb_addr_in_curr_slice = pps->ctb_addr_in_slice + pps->slice_start_offset[pic_level_slice_idx]; sh->num_ctus_in_curr_slice = pps->num_ctus_in_slice[pic_level_slice_idx]; } else { -- 2.52.0 >From 3f4400eb595cceaf59256dc72230851710607b30 Mon Sep 17 00:00:00 2001 From: Michael Niedermayer <[email protected]> Date: Tue, 6 Oct 2026 06:48:27 +0200 Subject: [PATCH 2/3] avcodec/vvc: Reject slices whose entry point walk does not match num_entry_points Hardening for ccSUzeWGhBGj Found-by: Umar Pathan (Umar0x) --- libavcodec/vvc/ps.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/libavcodec/vvc/ps.c b/libavcodec/vvc/ps.c index 4aa1f4767a..d40c8050db 100644 --- a/libavcodec/vvc/ps.c +++ b/libavcodec/vvc/ps.c @@ -1472,7 +1472,8 @@ static void sh_partition_constraints(VVCSH *sh, const H266RawSPS *sps, const H26 static int sh_entry_points(VVCSH *sh, const H266RawSPS *sps, const VVCPPS *pps) { if (sps->sps_entry_point_offsets_present_flag) { - for (int i = 1, j = 0; i < sh->num_ctus_in_curr_slice; i++) { + int j = 0; + for (int i = 1; i < sh->num_ctus_in_curr_slice; i++) { const int pre_ctb_addr_x = sh->ctb_addr_in_curr_slice[i - 1] % pps->ctb_width; const int pre_ctb_addr_y = sh->ctb_addr_in_curr_slice[i - 1] / pps->ctb_width; const int ctb_addr_x = sh->ctb_addr_in_curr_slice[i] % pps->ctb_width; @@ -1485,6 +1486,8 @@ static int sh_entry_points(VVCSH *sh, const H266RawSPS *sps, const VVCPPS *pps) sh->entry_point_start_ctu[j++] = i; } } + if (j != sh->r->num_entry_points) + return AVERROR_INVALIDDATA; } return 0; -- 2.52.0 >From 88736d765994b2abbf38ea5d11583ae1c8a14079 Mon Sep 17 00:00:00 2001 From: Michael Niedermayer <[email protected]> Date: Tue, 6 Oct 2026 23:20:08 +0200 Subject: [PATCH 3/3] avcodec/cbs_h266: Reject subpictures without slices Hardening for ccSUzeWGhBGj Found-by: Umar Pathan (Umar0x) --- libavcodec/cbs_h266_syntax_template.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libavcodec/cbs_h266_syntax_template.c b/libavcodec/cbs_h266_syntax_template.c index 6ad4039e1a..9e0776defe 100644 --- a/libavcodec/cbs_h266_syntax_template.c +++ b/libavcodec/cbs_h266_syntax_template.c @@ -2162,6 +2162,8 @@ static int FUNC(pps) (CodedBitstreamContext *ctx, RWContext *rw, current->num_slices_in_subpic[i]++; } } + if (!current->num_slices_in_subpic[i]) + return AVERROR_INVALIDDATA; num_slices += current->num_slices_in_subpic[i]; } if (current->pps_num_slices_in_pic_minus1 + 1 != num_slices) -- 2.52.0 _______________________________________________ ffmpeg-devel mailing list -- [email protected] To unsubscribe send an email to [email protected]
