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]

Reply via email to