PR #25603 opened by Kacper Michajłow (kasper93) URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/25603 Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/25603.patch
A colocated field picture always takes the field branch, but macroblocks that were never decoded in a broken field picture keep a stale mb_type without MB_TYPE_INTERLACED. The later IS_INTERLACED(mb_type_col[0]) check then picked the frame to frame path with the field remapping, which reads the colocated motion vectors past the end of the picture. Set the flag on the colocated type whenever the field branch is taken, decoded macroblocks have it already. Fixes: heap-buffer-overflow (read) Fixes: 553213954/clusterfuzz-testcase-minimized-fuzzer_loadfile_mkv-6112026834042880 Found-by: https://github.com/google/oss-fuzz/tree/master/projects/mpv From 7c27608e5cb2f9b7c2408b1f6bb9f1d3ac8e01d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kacper=20Michaj=C5=82ow?= <[email protected]> Date: Fri, 30 Oct 2026 01:43:12 +0100 Subject: [PATCH] avcodec/h264_direct: keep the colocated type interlaced in the field branch MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A colocated field picture always takes the field branch, but macroblocks that were never decoded in a broken field picture keep a stale mb_type without MB_TYPE_INTERLACED. The later IS_INTERLACED(mb_type_col[0]) check then picked the frame to frame path with the field remapping, which reads the colocated motion vectors past the end of the picture. Set the flag on the colocated type whenever the field branch is taken, decoded macroblocks have it already. Fixes: heap-buffer-overflow (read) Fixes: 553213954/clusterfuzz-testcase-minimized-fuzzer_loadfile_mkv-6112026834042880 Found-by: https://github.com/google/oss-fuzz/tree/master/projects/mpv Signed-off-by: Kacper Michajłow <[email protected]> --- libavcodec/h264_direct.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/libavcodec/h264_direct.c b/libavcodec/h264_direct.c index 1bc4f911ba3..44942f17a85 100644 --- a/libavcodec/h264_direct.c +++ b/libavcodec/h264_direct.c @@ -212,6 +212,7 @@ static void pred_spatial_direct_motion(const H264Context *const h, H264SliceCont int b4_stride = h->b_stride; int mb_xy = sl->mb_xy, mb_y = sl->mb_y; int mb_type_col[2]; + int col_field = 0; const int16_t (*l1mv0)[2], (*l1mv1)[2]; const int8_t *l1ref0, *l1ref1; const int is_b8x8 = IS_8X8(*mb_type); @@ -303,6 +304,9 @@ static void pred_spatial_direct_motion(const H264Context *const h, H264SliceCont mb_y += sl->col_fieldoff; mb_xy += h->mb_stride * sl->col_fieldoff; // non-zero for FL -> FL & differ parity } + // Undecoded macroblocks of a broken field picture lack the flag, the + // colocated type has to agree with the branch taken here. + col_field = MB_TYPE_INTERLACED; goto single_col; } else { // AFL/AFR/FR/FL -> AFR/FR if (IS_INTERLACED(*mb_type)) { // AFL /FL -> AFR/FR @@ -329,7 +333,7 @@ static void pred_spatial_direct_motion(const H264Context *const h, H264SliceCont } else { // AFR/FR -> AFR/FR single_col: mb_type_col[0] = - mb_type_col[1] = sl->ref_list[1][0].parent->mb_type[mb_xy]; + mb_type_col[1] = sl->ref_list[1][0].parent->mb_type[mb_xy] | col_field; sub_mb_type |= MB_TYPE_16x16 | MB_TYPE_DIRECT2; /* B_SUB_8x8 */ if (!is_b8x8 && (mb_type_col[0] & MB_TYPE_16x16_OR_INTRA)) { @@ -500,6 +504,7 @@ static void pred_temp_direct_motion(const H264Context *const h, H264SliceContext int b4_stride = h->b_stride; int mb_xy = sl->mb_xy, mb_y = sl->mb_y; int mb_type_col[2]; + int col_field = 0; const int16_t (*l1mv0)[2], (*l1mv1)[2]; const int8_t *l1ref0, *l1ref1; const int is_b8x8 = IS_8X8(*mb_type); @@ -522,6 +527,9 @@ static void pred_temp_direct_motion(const H264Context *const h, H264SliceContext mb_y += sl->col_fieldoff; mb_xy += h->mb_stride * sl->col_fieldoff; // non-zero for FL -> FL & differ parity } + // Undecoded macroblocks of a broken field picture lack the flag, the + // colocated type has to agree with the branch taken here. + col_field = MB_TYPE_INTERLACED; goto single_col; } else { // AFL/AFR/FR/FL -> AFR/FR if (IS_INTERLACED(*mb_type)) { // AFL /FL -> AFR/FR @@ -551,7 +559,7 @@ static void pred_temp_direct_motion(const H264Context *const h, H264SliceContext } else { // AFR/FR -> AFR/FR single_col: mb_type_col[0] = - mb_type_col[1] = sl->ref_list[1][0].parent->mb_type[mb_xy]; + mb_type_col[1] = sl->ref_list[1][0].parent->mb_type[mb_xy] | col_field; sub_mb_type = MB_TYPE_16x16 | MB_TYPE_P0L0 | MB_TYPE_P0L1 | MB_TYPE_DIRECT2; /* B_SUB_8x8 */ -- 2.54.0 _______________________________________________ ffmpeg-devel mailing list -- [email protected] To unsubscribe send an email to [email protected]
