PR #25569 opened by michaelni URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/25569 Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/25569.patch
>From 710b509a94231cac9d877325fe94d36ed825da07 Mon Sep 17 00:00:00 2001 From: Michael Niedermayer <[email protected]> Date: Wed, 28 Oct 2026 23:59:58 +0100 Subject: [PATCH 1/7] avcodec/bsf/pcm_rechunk: reject channel counts that overflow the sample size Fixes: Zc8wjsgxLWvu Fixes: AISLE-2026-0150-00562 Fixes: signed integer overflow, division by zero Division by zero Replicated through UnModified FFmpeg with ASAN and UBSAN Found-by: Joshua Rogers <[email protected]> --- libavcodec/bsf/pcm_rechunk.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/libavcodec/bsf/pcm_rechunk.c b/libavcodec/bsf/pcm_rechunk.c index 0c1007e2718..3f7d01226ca 100644 --- a/libavcodec/bsf/pcm_rechunk.c +++ b/libavcodec/bsf/pcm_rechunk.c @@ -41,13 +41,14 @@ static int init(AVBSFContext *ctx) PCMContext *s = ctx->priv_data; AVRational sr = av_make_q(ctx->par_in->sample_rate, 1); int64_t min_samples; + int bits_per_sample = av_get_bits_per_sample(ctx->par_in->codec_id); - if (ctx->par_in->ch_layout.nb_channels <= 0 || ctx->par_in->sample_rate <= 0) + if (ctx->par_in->ch_layout.nb_channels <= 0 || ctx->par_in->sample_rate <= 0 || + ctx->par_in->ch_layout.nb_channels > INT_MAX / bits_per_sample) return AVERROR(EINVAL); ctx->time_base_out = av_inv_q(sr); - s->sample_size = ctx->par_in->ch_layout.nb_channels * - av_get_bits_per_sample(ctx->par_in->codec_id) / 8; + s->sample_size = ctx->par_in->ch_layout.nb_channels * bits_per_sample / 8; if (s->frame_rate.num) { min_samples = av_rescale_q_rnd(1, sr, s->frame_rate, AV_ROUND_DOWN); -- 2.54.0 >From fc70a505d2e71cab404c9b510435390f8a648c96 Mon Sep 17 00:00:00 2001 From: Michael Niedermayer <[email protected]> Date: Thu, 29 Oct 2026 00:00:03 +0100 Subject: [PATCH 2/7] avcodec/bsf/aac_adtstoasc: check the bit reader initialization before the PCE Fixes: RG0je5bJzuAD Fixes: AISLE-2026-0150-00525 Fixes: NULL pointer dereference NULL pointer dereference Replicated through UnModified FFmpeg with ASAN and UBSAN Found-by: Joshua Rogers <[email protected]> --- libavcodec/bsf/aac_adtstoasc.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/libavcodec/bsf/aac_adtstoasc.c b/libavcodec/bsf/aac_adtstoasc.c index dd6e8e8a385..9f8e61e4228 100644 --- a/libavcodec/bsf/aac_adtstoasc.c +++ b/libavcodec/bsf/aac_adtstoasc.c @@ -79,7 +79,9 @@ static int aac_adtstoasc_filter(AVBSFContext *bsfc, AVPacket *pkt) if (!hdr.chan_config) { GetBitContext gb; - init_get_bits(&gb, pkt->data, pkt->size * 8); + ret = init_get_bits8(&gb, pkt->data, pkt->size); + if (ret < 0) + goto fail; if (get_bits(&gb, 3) != 5) { avpriv_report_missing_feature(bsfc, "PCE-based channel configuration " -- 2.54.0 >From cf5344e671f1c8a54d91d5a22fc356e7823d2095 Mon Sep 17 00:00:00 2001 From: Michael Niedermayer <[email protected]> Date: Thu, 29 Oct 2026 00:00:07 +0100 Subject: [PATCH 3/7] avcodec/jpegxl_parser: stop before a TOC that cannot fit in the input Fixes: QbQGn4p3g48Q Fixes: AISLE-2026-0150-00842 Fixes: Timeout Timeout Replicated through UnModified FFmpeg with /usr/bin/time Found-by: Joshua Rogers <[email protected]> --- libavcodec/jpegxl_parser.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/libavcodec/jpegxl_parser.c b/libavcodec/jpegxl_parser.c index 902a1532aac..5b64347726d 100644 --- a/libavcodec/jpegxl_parser.c +++ b/libavcodec/jpegxl_parser.c @@ -1317,6 +1317,10 @@ static int parse_frame_header(void *avctx, JXLParseContext *ctx, GetBitContext * else toc_count = 2 + num_lf_groups + num_groups * num_passes; + /* each TOC entry takes at least 12 bits */ + if ((int64_t)toc_count * 12 > get_bits_left(gb)) + return AVERROR_BUFFER_TOO_SMALL; + // permuted toc if (get_bits1(gb)) { JXLEntropyDecoder dec; -- 2.54.0 >From e972be4f3210e6e04d7af53c2b9352e5f2177529 Mon Sep 17 00:00:00 2001 From: Michael Niedermayer <[email protected]> Date: Thu, 29 Oct 2026 00:00:11 +0100 Subject: [PATCH 4/7] avcodec/bsf/dts2pts: reject packets with more than two H.264 pictures Fixes: iYUViL6T5SOa Fixes: AISLE-2026-0150-00073 Fixes: Timeout Timeout Replicated through UnModified FFmpeg with /usr/bin/time Found-by: Joshua Rogers <[email protected]> --- libavcodec/bsf/dts2pts.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/libavcodec/bsf/dts2pts.c b/libavcodec/bsf/dts2pts.c index 03e7c399832..6d86a2cf5dd 100644 --- a/libavcodec/bsf/dts2pts.c +++ b/libavcodec/bsf/dts2pts.c @@ -264,7 +264,7 @@ static int h264_filter(AVBSFContext *ctx) AVPacket *in; int output_picture_number = INT_MIN; int field_poc[2]; - int queued = 0, ret; + int queued = 0, nb_pictures = 0, ret; ret = ff_bsf_get_packet(ctx, &in); if (ret < 0) @@ -340,6 +340,11 @@ static int h264_filter(AVBSFContext *ctx) } if (output_picture_number != h264->last_poc) { + if (++nb_pictures > 2) { + av_log(ctx, AV_LOG_ERROR, "More than two pictures in a packet\n"); + ret = AVERROR_INVALIDDATA; + goto fail; + } if (h264->last_poc != INT_MIN) { int64_t diff = FFABS(h264->last_poc - (int64_t)output_picture_number); -- 2.54.0 >From 397fe9cc2138d56f3d6f52698528e85ce6099036 Mon Sep 17 00:00:00 2001 From: Michael Niedermayer <[email protected]> Date: Thu, 29 Oct 2026 00:00:14 +0100 Subject: [PATCH 5/7] avformat/mux: do not overflow the default block_align computation Fixes: 6nHC3ciDJMZ6 Fixes: signed integer overflow Signed integer overflow Replicated through UnModified FFmpeg with UBSAN Found during triage of the security report Zc8wjsgxLWvu --- libavformat/mux.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/libavformat/mux.c b/libavformat/mux.c index 8226840b4c7..a5d1cc34c64 100644 --- a/libavformat/mux.c +++ b/libavformat/mux.c @@ -241,9 +241,16 @@ static int init_muxer(AVFormatContext *s, AVDictionary **options) goto fail; } - if (!par->block_align) - par->block_align = par->ch_layout.nb_channels * - av_get_bits_per_sample(par->codec_id) >> 3; + if (!par->block_align) { + int64_t block_align = (int64_t)par->ch_layout.nb_channels * + av_get_bits_per_sample(par->codec_id) >> 3; + if (block_align > INT_MAX) { + av_log(s, AV_LOG_ERROR, "too many channels\n"); + ret = AVERROR(EINVAL); + goto fail; + } + par->block_align = block_align; + } break; case AVMEDIA_TYPE_VIDEO: if ((par->width <= 0 || par->height <= 0) && -- 2.54.0 >From 5d2c2c40b3ffa501d282ae990c43f8a7d2daa297 Mon Sep 17 00:00:00 2001 From: Michael Niedermayer <[email protected]> Date: Thu, 29 Oct 2026 00:00:18 +0100 Subject: [PATCH 6/7] avcodec/bsf/av1_frame_merge: limit the number of OBUs buffered per temporal unit Fixes: bdTY8jUuDHwF Fixes: AISLE-2026-0150-00241 Fixes: OOM OOM Replicated through UnModified FFmpeg with /usr/bin/time (peak RSS) Found-by: Joshua Rogers <[email protected]> --- libavcodec/bsf/av1_frame_merge.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/libavcodec/bsf/av1_frame_merge.c b/libavcodec/bsf/av1_frame_merge.c index 12d53fba7ca..67d16e1c317 100644 --- a/libavcodec/bsf/av1_frame_merge.c +++ b/libavcodec/bsf/av1_frame_merge.c @@ -23,6 +23,8 @@ #include "libavcodec/cbs.h" #include "libavcodec/cbs_av1.h" +#define MAX_TU_OBUS (1 << 16) + typedef struct AV1FMergeContext { CodedBitstreamContext *input; CodedBitstreamContext *output; @@ -93,6 +95,11 @@ eof: // Swap fragment index, to avoid copying fragment references. ctx->idx = !ctx->idx; } else { + if (tu->nb_units + frag->nb_units > MAX_TU_OBUS) { + av_log(bsf, AV_LOG_ERROR, "Too many OBUs in a Temporal Unit.\n"); + err = AVERROR_INVALIDDATA; + goto fail; + } for (i = 0; i < frag->nb_units; i++) { err = ff_cbs_insert_unit_content(tu, -1, frag->units[i].type, frag->units[i].content, frag->units[i].content_ref); -- 2.54.0 >From 2d31434f69ea89d7bcc33b52486de69095d4bc89 Mon Sep 17 00:00:00 2001 From: Michael Niedermayer <[email protected]> Date: Thu, 29 Oct 2026 00:00:23 +0100 Subject: [PATCH 7/7] avcodec/flac_parser: score the header chain without recursion Fixes: iEdHjyvZ3jOg Fixes: AISLE-2026-0150-00454 Fixes: stack overflow Stack overflow Replicated through API with a 512 KB stack limit Found-by: Joshua Rogers <[email protected]> --- libavcodec/flac_parser.c | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/libavcodec/flac_parser.c b/libavcodec/flac_parser.c index 9a5f5fd03a0..f50b0b262d7 100644 --- a/libavcodec/flac_parser.c +++ b/libavcodec/flac_parser.c @@ -75,6 +75,8 @@ typedef struct FLACHeaderMarker { struct FLACHeaderMarker *next; /**< next CRC-8 verified header that immediately follows this one in the bytestream */ + struct FLACHeaderMarker *prev; /**< CRC-8 verified header that + immediately precedes this one */ struct FLACHeaderMarker *best_child; /**< following frame header with which this frame has the best score with */ @@ -321,11 +323,12 @@ static int find_headers_search_validate(FLACParseContext *fpc, int offset) &fpc->wrap_buf, &fpc->wrap_buf_allocated_size); if (frame_header_is_valid(fpc->avctx, header_buf, &fi)) { - FLACHeaderMarker **end_handle = &fpc->headers; + FLACHeaderMarker **end_handle = &fpc->headers, *prev = NULL; int i; size = 0; while (*end_handle) { + prev = *end_handle; end_handle = &(*end_handle)->next; size++; } @@ -338,6 +341,7 @@ static int find_headers_search_validate(FLACParseContext *fpc, int offset) } (*end_handle)->fi = fi; (*end_handle)->offset = offset; + (*end_handle)->prev = prev; for (i = 0; i < FLAC_MAX_SEQUENTIAL_HEADERS; i++) (*end_handle)->link_penalty[i] = FLAC_HEADER_NOT_PENALIZED_YET; @@ -615,15 +619,18 @@ static int score_header(FLACParseContext *fpc, FLACHeaderMarker *header) static void score_sequences(FLACParseContext *fpc) { - FLACHeaderMarker *curr; + FLACHeaderMarker *curr, *last = NULL; int best_score = FLAC_HEADER_NOT_SCORED_YET; /* First pass to clear all old scores. */ - for (curr = fpc->headers; curr; curr = curr->next) - curr->max_score = FLAC_HEADER_NOT_SCORED_YET; - - /* Do a second pass to score them all. */ for (curr = fpc->headers; curr; curr = curr->next) { - if (score_header(fpc, curr) > best_score) { + curr->max_score = FLAC_HEADER_NOT_SCORED_YET; + last = curr; + } + + /* Score from the last header backwards, so the children of each header + are already scored and score_header() does not recurse. */ + for (curr = last; curr; curr = curr->prev) { + if (score_header(fpc, curr) >= best_score) { fpc->best_header = curr; best_score = curr->max_score; } @@ -728,6 +735,7 @@ static int flac_parse(AVCodecParserContext *s, AVCodecContext *avctx, curr->offset -= best_child->offset; best_child->offset = 0; + best_child->prev = NULL; fpc->headers = best_child; if (fpc->nb_headers_buffered >= FLAC_MIN_HEADERS) { fpc->best_header = best_child; @@ -744,6 +752,8 @@ static int flac_parse(AVCodecParserContext *s, AVCodecContext *avctx, fpc->nb_headers_buffered--; } fpc->headers = fpc->best_header->next; + if (fpc->headers) + fpc->headers->prev = NULL; av_freep(&fpc->best_header); fpc->nb_headers_buffered--; } -- 2.54.0 _______________________________________________ ffmpeg-devel mailing list -- [email protected] To unsubscribe send an email to [email protected]
