PR #21759 opened by michaelni URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/21759 Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/21759.patch
avcodec/cfhd: Check transform type before continuing. Fixes: null pointer dereference Fixes: 471768165/clusterfuzz-testcase-minimized-ffmpeg_AV_CODEC_ID_CFHD_DEC_fuzzer-6187504467509248 The first frame allocates buffers with one transform type the second frame sets up another transform type but the code to reallocate buffers is never triggered Found-by: continuous fuzzing process https://github.com/google/oss-fuzz/tree/master/projects/ffmpeg Signed-off-by: Michael Niedermayer <[email protected]> >From 56c7b802d04419f56ce577f9d9d1d06a7ba9c287 Mon Sep 17 00:00:00 2001 From: Michael Niedermayer <[email protected]> Date: Sat, 14 Feb 2026 23:00:02 +0100 Subject: [PATCH 1/2] avcodec/cfhd: Add CFHDSegment enum and named identifiers Signed-off-by: Michael Niedermayer <[email protected]> --- libavcodec/cfhd.c | 4 ++-- libavcodec/cfhd.h | 9 +++++++++ libavcodec/cfhdenc.c | 12 ++++++------ 3 files changed, 17 insertions(+), 8 deletions(-) diff --git a/libavcodec/cfhd.c b/libavcodec/cfhd.c index f110b91f0b..6d1cf4b67b 100644 --- a/libavcodec/cfhd.c +++ b/libavcodec/cfhd.c @@ -631,7 +631,7 @@ static int cfhd_decode(AVCodecContext *avctx, AVFrame *pic, } else av_log(avctx, AV_LOG_DEBUG, "Unknown tag %i data %x\n", tag, data); - if (tag == BitstreamMarker && data == 0xf0f && + if (tag == BitstreamMarker && data == CoefficientSegment && s->coded_format != AV_PIX_FMT_NONE) { int lowpass_height = s->plane[s->channel_num].band[0][0].height; int lowpass_width = s->plane[s->channel_num].band[0][0].width; @@ -701,7 +701,7 @@ static int cfhd_decode(AVCodecContext *avctx, AVFrame *pic, coeff_data = s->plane[s->channel_num].subband[s->subband_num_actual]; /* Lowpass coefficients */ - if (tag == BitstreamMarker && data == 0xf0f) { + if (tag == BitstreamMarker && data == CoefficientSegment) { int lowpass_height, lowpass_width, lowpass_a_height, lowpass_a_width; if (!s->a_width || !s->a_height) { diff --git a/libavcodec/cfhd.h b/libavcodec/cfhd.h index 2dbac80c66..880c0e1e9d 100644 --- a/libavcodec/cfhd.h +++ b/libavcodec/cfhd.h @@ -91,6 +91,15 @@ enum CFHDParam { ChannelHeight = 105, }; +enum CFHDSegment { + LowPassSegment = 0x1a4a, + LowPassEndSegment = 0x1b4b, + HighPassSegment = 0x0d0d, + BandSegment = 0x0e0e, + HighPassEndSegment = 0x0c0c, + CoefficientSegment = 0x0f0f, +}; + #define VLC_BITS 9 #define SUBBAND_COUNT 10 #define SUBBAND_COUNT_3D 17 diff --git a/libavcodec/cfhdenc.c b/libavcodec/cfhdenc.c index 42e01bfd85..db435f321c 100644 --- a/libavcodec/cfhdenc.c +++ b/libavcodec/cfhdenc.c @@ -627,7 +627,7 @@ static int cfhd_encode_frame(AVCodecContext *avctx, AVPacket *pkt, } bytestream2_put_be16(pby, BitstreamMarker); - bytestream2_put_be16(pby, 0x1a4a); + bytestream2_put_be16(pby, LowPassSegment); pos = bytestream2_tell_p(pby); @@ -653,7 +653,7 @@ static int cfhd_encode_frame(AVCodecContext *avctx, AVPacket *pkt, bytestream2_put_be16(pby, 16); bytestream2_put_be16(pby, BitstreamMarker); - bytestream2_put_be16(pby, 0x0f0f); + bytestream2_put_be16(pby, CoefficientSegment); for (int i = 0; i < height; i++) { for (int j = 0; j < width; j++) @@ -662,7 +662,7 @@ static int cfhd_encode_frame(AVCodecContext *avctx, AVPacket *pkt, } bytestream2_put_be16(pby, BitstreamMarker); - bytestream2_put_be16(pby, 0x1b4b); + bytestream2_put_be16(pby, LowPassEndSegment); for (int l = 0; l < 3; l++) { for (int i = 0; i < 3; i++) { @@ -677,7 +677,7 @@ static int cfhd_encode_frame(AVCodecContext *avctx, AVPacket *pkt, int height = s->plane[p].band[l][0].height; bytestream2_put_be16(pby, BitstreamMarker); - bytestream2_put_be16(pby, 0x0d0d); + bytestream2_put_be16(pby, HighPassSegment); bytestream2_put_be16(pby, WaveletType); bytestream2_put_be16(pby, 3 + 2 * (l == 2)); @@ -714,7 +714,7 @@ static int cfhd_encode_frame(AVCodecContext *avctx, AVPacket *pkt, int count = 0, padd = 0; bytestream2_put_be16(pby, BitstreamMarker); - bytestream2_put_be16(pby, 0x0e0e); + bytestream2_put_be16(pby, BandSegment); bytestream2_put_be16(pby, SubbandNumber); bytestream2_put_be16(pby, i + 1); @@ -783,7 +783,7 @@ static int cfhd_encode_frame(AVCodecContext *avctx, AVPacket *pkt, } bytestream2_put_be16(pby, BitstreamMarker); - bytestream2_put_be16(pby, 0x0c0c); + bytestream2_put_be16(pby, HighPassEndSegment); } s->plane[p].size = bytestream2_tell_p(pby) - pos; -- 2.52.0 >From 0b97c9938e518fd03ef8699e86d60773ec1a6010 Mon Sep 17 00:00:00 2001 From: Michael Niedermayer <[email protected]> Date: Sun, 15 Feb 2026 00:00:55 +0100 Subject: [PATCH 2/2] avcodec/cfhd: Check transform type before continuing Fixes: null pointer dereference Fixes: 471768165/clusterfuzz-testcase-minimized-ffmpeg_AV_CODEC_ID_CFHD_DEC_fuzzer-6187504467509248 The first frame allocates buffers with one transform type the second frame sets up another transform type but the code to reallocate buffers is never triggered Found-by: continuous fuzzing process https://github.com/google/oss-fuzz/tree/master/projects/ffmpeg Signed-off-by: Michael Niedermayer <[email protected]> --- libavcodec/cfhd.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/libavcodec/cfhd.c b/libavcodec/cfhd.c index 6d1cf4b67b..4d430e32ef 100644 --- a/libavcodec/cfhd.c +++ b/libavcodec/cfhd.c @@ -698,6 +698,11 @@ static int cfhd_decode(AVCodecContext *avctx, AVFrame *pic, if (s->subband_num_actual == 255) goto finish; + + if (tag == BitstreamMarker && data == CoefficientSegment || tag == BandHeader || tag == BandSecondPass || s->peak.level) + if (s->transform_type != s->a_transform_type) + return AVERROR_PATCHWELCOME; + coeff_data = s->plane[s->channel_num].subband[s->subband_num_actual]; /* Lowpass coefficients */ -- 2.52.0 _______________________________________________ ffmpeg-devel mailing list -- [email protected] To unsubscribe send an email to [email protected]
