Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
 help / color / mirror / Atom feed
* [FFmpeg-devel] [PR] avcodec/hevc/ps: Check window parameters (PR #22277)
@ 2026-02-24 15:45 James Almer via ffmpeg-devel
  0 siblings, 0 replies; only message in thread
From: James Almer via ffmpeg-devel @ 2026-02-24 15:45 UTC (permalink / raw)
  To: ffmpeg-devel; +Cc: James Almer

PR #22277 opened by James Almer (jamrial)
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/22277
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/22277.patch


>From 97023345f64d0d85b4ec6cc89ffbc9a966f730ab Mon Sep 17 00:00:00 2001
From: Michael Niedermayer <michael@niedermayer.cc>
Date: Sun, 22 Feb 2026 21:50:37 +0100
Subject: [PATCH 1/2] avcodec/hevc/ps: Factor window reading out

Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
---
 libavcodec/hevc/ps.c | 52 +++++++++++++++++++++++++-------------------
 libavcodec/hevc/ps.h |  5 +----
 2 files changed, 31 insertions(+), 26 deletions(-)

diff --git a/libavcodec/hevc/ps.c b/libavcodec/hevc/ps.c
index 46b38564d5..ca2b8a7112 100644
--- a/libavcodec/hevc/ps.c
+++ b/libavcodec/hevc/ps.c
@@ -62,6 +62,22 @@ static const uint8_t hevc_sub_height_c[] = {
     1, 2, 1, 1
 };
 
+static int read_window(HEVCWindow *window, GetBitContext *gb, int chroma_format_idc, int w, int h)
+{
+    int vert_mult  = hevc_sub_height_c[chroma_format_idc];
+    int horiz_mult = hevc_sub_width_c [chroma_format_idc];
+    unsigned left   = get_ue_golomb_long(gb) * horiz_mult;
+    unsigned right  = get_ue_golomb_long(gb) * horiz_mult;
+    unsigned top    = get_ue_golomb_long(gb) * vert_mult;
+    unsigned bottom = get_ue_golomb_long(gb) * vert_mult;
+
+    window->left_offset   = left;
+    window->right_offset  = right;
+    window->top_offset    = top;
+    window->bottom_offset = bottom;
+    return 0;
+}
+
 static void remove_sps(HEVCParamSets *s, int id)
 {
     int i;
@@ -702,12 +718,12 @@ static int decode_vps_ext(GetBitContext *gb, AVCodecContext *avctx, HEVCVPS *vps
     }
 
     if (get_bits1(gb) /* conformance_window_vps_flag */) {
-        int vert_mult  = hevc_sub_height_c[vps->rep_format.chroma_format_idc];
-        int horiz_mult = hevc_sub_width_c[vps->rep_format.chroma_format_idc];
-        vps->rep_format.conf_win_left_offset   = get_ue_golomb(gb) * horiz_mult;
-        vps->rep_format.conf_win_right_offset  = get_ue_golomb(gb) * horiz_mult;
-        vps->rep_format.conf_win_top_offset    = get_ue_golomb(gb) * vert_mult;
-        vps->rep_format.conf_win_bottom_offset = get_ue_golomb(gb) * vert_mult;
+        int ret = read_window(&vps->rep_format.conf_win, gb,
+                              vps->rep_format.chroma_format_idc,
+                              vps->rep_format.pic_width_in_luma_samples,
+                              vps->rep_format.pic_height_in_luma_samples);
+        if (ret < 0)
+            return ret;
     }
 
     vps->max_one_active_ref_layer = get_bits1(gb);
@@ -962,12 +978,7 @@ static void decode_vui(GetBitContext *gb, AVCodecContext *avctx,
         vui->default_display_window_flag = get_bits1(gb);
 
     if (vui->default_display_window_flag) {
-        int vert_mult  = hevc_sub_height_c[sps->chroma_format_idc];
-        int horiz_mult = hevc_sub_width_c[sps->chroma_format_idc];
-        vui->def_disp_win.left_offset   = get_ue_golomb_long(gb) * horiz_mult;
-        vui->def_disp_win.right_offset  = get_ue_golomb_long(gb) * horiz_mult;
-        vui->def_disp_win.top_offset    = get_ue_golomb_long(gb) *  vert_mult;
-        vui->def_disp_win.bottom_offset = get_ue_golomb_long(gb) *  vert_mult;
+        read_window(&vui->def_disp_win, gb, sps->chroma_format_idc, sps->width, sps->height);
 
         if (apply_defdispwin &&
             avctx->flags2 & AV_CODEC_FLAG2_IGNORE_CROP) {
@@ -1281,10 +1292,10 @@ int ff_hevc_parse_sps(HEVCSPS *sps, GetBitContext *gb, unsigned int *sps_id,
         sps->width                 = rf->pic_width_in_luma_samples;
         sps->height                = rf->pic_height_in_luma_samples;
 
-        sps->pic_conf_win.left_offset   = rf->conf_win_left_offset;
-        sps->pic_conf_win.right_offset  = rf->conf_win_right_offset;
-        sps->pic_conf_win.top_offset    = rf->conf_win_top_offset;
-        sps->pic_conf_win.bottom_offset = rf->conf_win_bottom_offset;
+        sps->pic_conf_win.left_offset   = rf->conf_win.left_offset;
+        sps->pic_conf_win.right_offset  = rf->conf_win.right_offset;
+        sps->pic_conf_win.top_offset    = rf->conf_win.top_offset;
+        sps->pic_conf_win.bottom_offset = rf->conf_win.bottom_offset;
 
     } else {
         sps->chroma_format_idc = get_ue_golomb_long(gb);
@@ -1307,12 +1318,9 @@ int ff_hevc_parse_sps(HEVCSPS *sps, GetBitContext *gb, unsigned int *sps_id,
 
         sps->conformance_window = get_bits1(gb);
         if (sps->conformance_window) {
-            int vert_mult  = hevc_sub_height_c[sps->chroma_format_idc];
-            int horiz_mult = hevc_sub_width_c[sps->chroma_format_idc];
-            sps->pic_conf_win.left_offset   = get_ue_golomb_long(gb) * horiz_mult;
-            sps->pic_conf_win.right_offset  = get_ue_golomb_long(gb) * horiz_mult;
-            sps->pic_conf_win.top_offset    = get_ue_golomb_long(gb) *  vert_mult;
-            sps->pic_conf_win.bottom_offset = get_ue_golomb_long(gb) *  vert_mult;
+            ret = read_window(&sps->pic_conf_win, gb, sps->chroma_format_idc, sps->width, sps->height);
+            if (ret < 0)
+                return ret;
 
             if (avctx->flags2 & AV_CODEC_FLAG2_IGNORE_CROP) {
                 av_log(avctx, AV_LOG_DEBUG,
diff --git a/libavcodec/hevc/ps.h b/libavcodec/hevc/ps.h
index d620887b8e..f5c5f81a6e 100644
--- a/libavcodec/hevc/ps.h
+++ b/libavcodec/hevc/ps.h
@@ -162,10 +162,7 @@ typedef struct RepFormat {
     uint8_t  separate_colour_plane_flag;
     uint8_t  bit_depth_luma;    ///< bit_depth_vps_luma_minus8 + 8
     uint8_t  bit_depth_chroma;  ///< bit_depth_vps_chroma_minus8 + 8
-    uint16_t conf_win_left_offset;
-    uint16_t conf_win_right_offset;
-    uint16_t conf_win_top_offset;
-    uint16_t conf_win_bottom_offset;
+    HEVCWindow conf_win;
 } RepFormat;
 
 typedef struct HEVCVPS {
-- 
2.52.0


>From 3b3127850a2565c62c4d8d982ff1f5dad3de371c Mon Sep 17 00:00:00 2001
From: James Almer <jamrial@gmail.com>
Date: Tue, 24 Feb 2026 12:33:47 -0300
Subject: [PATCH 2/2] avcodec/hevc/ps: Check window parameters

Fixes: signed integer overflow: -1094995529 * 2 cannot be represented in type 'int'
Fixes: 484567435/clusterfuzz-testcase-minimized-ffmpeg_dem_HXVS_fuzzer-5628836988649472

Found-by: continuous fuzzing process https://github.com/google/oss-fuzz/tree/master/projects/ffmpeg
Signed-off-by: James Almer <jamrial@gmail.com>
---
 libavcodec/hevc/ps.c | 48 +++++++++++++++++++++++++++-----------------
 1 file changed, 30 insertions(+), 18 deletions(-)

diff --git a/libavcodec/hevc/ps.c b/libavcodec/hevc/ps.c
index ca2b8a7112..df4039a2a3 100644
--- a/libavcodec/hevc/ps.c
+++ b/libavcodec/hevc/ps.c
@@ -66,15 +66,19 @@ static int read_window(HEVCWindow *window, GetBitContext *gb, int chroma_format_
 {
     int vert_mult  = hevc_sub_height_c[chroma_format_idc];
     int horiz_mult = hevc_sub_width_c [chroma_format_idc];
-    unsigned left   = get_ue_golomb_long(gb) * horiz_mult;
-    unsigned right  = get_ue_golomb_long(gb) * horiz_mult;
-    unsigned top    = get_ue_golomb_long(gb) * vert_mult;
-    unsigned bottom = get_ue_golomb_long(gb) * vert_mult;
+    unsigned left   = get_ue_golomb_long(gb);
+    unsigned right  = get_ue_golomb_long(gb);
+    unsigned top    = get_ue_golomb_long(gb);
+    unsigned bottom = get_ue_golomb_long(gb);
 
-    window->left_offset   = left;
-    window->right_offset  = right;
-    window->top_offset    = top;
-    window->bottom_offset = bottom;
+    if (left > w || right  > w ||
+        top  > h || bottom > h)
+        return AVERROR_INVALIDDATA;
+
+    window->left_offset   = left   * horiz_mult;
+    window->right_offset  = right  * horiz_mult;
+    window->top_offset    = top    * vert_mult;
+    window->bottom_offset = bottom * vert_mult;
     return 0;
 }
 
@@ -699,6 +703,10 @@ static int decode_vps_ext(GetBitContext *gb, AVCodecContext *avctx, HEVCVPS *vps
     vps->rep_format.pic_width_in_luma_samples  = get_bits(gb, 16);
     vps->rep_format.pic_height_in_luma_samples = get_bits(gb, 16);
 
+    if (vps->rep_format.pic_width_in_luma_samples  > HEVC_MAX_WIDTH ||
+        vps->rep_format.pic_height_in_luma_samples > HEVC_MAX_HEIGHT)
+        return AVERROR_INVALIDDATA;
+
     if (!get_bits1(gb) /* chroma_and_bit_depth_vps_present_flag */) {
         av_log(avctx, AV_LOG_ERROR,
                "chroma_and_bit_depth_vps_present_flag=0 in first rep_format\n");
@@ -935,7 +943,7 @@ err:
     return ret;
 }
 
-static void decode_vui(GetBitContext *gb, AVCodecContext *avctx,
+static int decode_vui(GetBitContext *gb, AVCodecContext *avctx,
                        int apply_defdispwin, HEVCSPS *sps)
 {
     VUI backup_vui, *vui = &sps->vui;
@@ -978,7 +986,7 @@ static void decode_vui(GetBitContext *gb, AVCodecContext *avctx,
         vui->default_display_window_flag = get_bits1(gb);
 
     if (vui->default_display_window_flag) {
-        read_window(&vui->def_disp_win, gb, sps->chroma_format_idc, sps->width, sps->height);
+        int ret = read_window(&vui->def_disp_win, gb, sps->chroma_format_idc, sps->width, sps->height);
 
         if (apply_defdispwin &&
             avctx->flags2 & AV_CODEC_FLAG2_IGNORE_CROP) {
@@ -994,7 +1002,8 @@ static void decode_vui(GetBitContext *gb, AVCodecContext *avctx,
             vui->def_disp_win.right_offset  =
             vui->def_disp_win.top_offset    =
             vui->def_disp_win.bottom_offset = 0;
-        }
+        } else if (ret < 0)
+            return ret;
     }
 
 timing_info:
@@ -1055,6 +1064,8 @@ timing_info:
         alt = 1;
         goto timing_info;
     }
+
+    return 0;
 }
 
 static void set_default_scaling_list_data(ScalingList *sl)
@@ -1312,15 +1323,12 @@ int ff_hevc_parse_sps(HEVCSPS *sps, GetBitContext *gb, unsigned int *sps_id,
 
         sps->width  = get_ue_golomb_long(gb);
         sps->height = get_ue_golomb_long(gb);
-        if ((ret = av_image_check_size(sps->width,
-                                       sps->height, 0, avctx)) < 0)
+        if (sps->width > HEVC_MAX_WIDTH || sps->height > HEVC_MAX_HEIGHT)
             return ret;
 
         sps->conformance_window = get_bits1(gb);
         if (sps->conformance_window) {
             ret = read_window(&sps->pic_conf_win, gb, sps->chroma_format_idc, sps->width, sps->height);
-            if (ret < 0)
-                return ret;
 
             if (avctx->flags2 & AV_CODEC_FLAG2_IGNORE_CROP) {
                 av_log(avctx, AV_LOG_DEBUG,
@@ -1335,7 +1343,8 @@ int ff_hevc_parse_sps(HEVCSPS *sps, GetBitContext *gb, unsigned int *sps_id,
                 sps->pic_conf_win.right_offset  =
                 sps->pic_conf_win.top_offset    =
                 sps->pic_conf_win.bottom_offset = 0;
-            }
+            } else if (ret < 0)
+                return ret;
         }
 
         sps->bit_depth = get_ue_golomb_31(gb) + 8;
@@ -1512,8 +1521,11 @@ int ff_hevc_parse_sps(HEVCSPS *sps, GetBitContext *gb, unsigned int *sps_id,
     sps->strong_intra_smoothing_enabled = get_bits1(gb);
     sps->vui.common.sar = (AVRational){0, 1};
     sps->vui_present = get_bits1(gb);
-    if (sps->vui_present)
-        decode_vui(gb, avctx, apply_defdispwin, sps);
+    if (sps->vui_present) {
+        ret = decode_vui(gb, avctx, apply_defdispwin, sps);
+        if (ret < 0)
+            return ret;
+    }
 
     sps->extension_present = get_bits1(gb);
     if (sps->extension_present) {
-- 
2.52.0

_______________________________________________
ffmpeg-devel mailing list -- ffmpeg-devel@ffmpeg.org
To unsubscribe send an email to ffmpeg-devel-leave@ffmpeg.org

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2026-02-24 21:42 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-02-24 15:45 [FFmpeg-devel] [PR] avcodec/hevc/ps: Check window parameters (PR #22277) James Almer via ffmpeg-devel

Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

This inbox may be cloned and mirrored by anyone:

	git clone --mirror https://master.gitmailbox.com/ffmpegdev/0 ffmpegdev/git/0.git

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V2 ffmpegdev ffmpegdev/ https://master.gitmailbox.com/ffmpegdev \
		ffmpegdev@gitmailbox.com
	public-inbox-index ffmpegdev

Example config snippet for mirrors.


AGPL code for this site: git clone https://public-inbox.org/public-inbox.git