[PR] avcodec/shorten: fix AVERROR_BUG during draining with invalid data (PR #24237)

aolinf via ffmpeg-devel <[email protected]>
Newsgroups gmane.comp.video.ffmpeg.devel
Message-ID <[email protected]>
PR #24237 opened by aolinf
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/24237
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/24237.patch

The shorten decoder declares AV_CODEC_CAP_DELAY but does not handle
draining (empty) packets safely. During draining, the decoder retries
decoding stale data from its internal buffer, returning
AVERROR_INVALIDDATA on every call until decode.c's safety counter
overflows and returns AVERROR_BUG, crashing the fuzzer harness
assertion.

Additionally, in container formats where extradata_size > 0,
read_header() skips audio header parsing (goto end). If extradata is
corrupted or fuzzed without setting valid audio parameters, outputting a
frame causes decode.c to assert AVERROR_BUG ("An invalid frame was
output by a decoder").

Fix both issues inside shorten_decode_frame():
1. During draining (!avpkt->data), allow decode to proceed normally with
   buffered data (so multi-block buffers are fully drained). At
   finish_frame, if no frame was produced, clear the buffer so
   subsequent drain calls return EOF without retrying stale data.
2. Validate sample_rate and ch_layout after read_header(s) returns,
   ensuring uninitialized extradata fails cleanly with
   AVERROR_INVALIDDATA instead of emitting an invalid frame.

Signed-off-by: Aolin Feng <[email protected]>



>From 66e1725318935823ffa8bbda087fc23fb47277c9 Mon Sep 17 00:00:00 2001
From: Aolin Feng <[email protected]>
Date: Thu, 23 Jul 2026 18:00:00 +0000
Subject: [PATCH] avcodec/shorten: fix AVERROR_BUG during draining with invalid
 data

The shorten decoder declares AV_CODEC_CAP_DELAY but does not handle
draining (empty) packets safely. During draining, the decoder retries
decoding stale data from its internal buffer, returning
AVERROR_INVALIDDATA on every call until decode.c's safety counter
overflows and returns AVERROR_BUG, crashing the fuzzer harness
assertion.

Additionally, in container formats where extradata_size > 0,
read_header() skips audio header parsing (goto end). If extradata is
corrupted or fuzzed without setting valid audio parameters, outputting a
frame causes decode.c to assert AVERROR_BUG ("An invalid frame was
output by a decoder").

Fix both issues inside shorten_decode_frame():
1. During draining (!avpkt->data), allow decode to proceed normally with
   buffered data (so multi-block buffers are fully drained). At
   finish_frame, if no frame was produced, clear the buffer so
   subsequent drain calls return EOF without retrying stale data.
2. Validate sample_rate and ch_layout after read_header(s) returns,
   ensuring uninitialized extradata fails cleanly with
   AVERROR_INVALIDDATA instead of emitting an invalid frame.

Signed-off-by: Aolin Feng <[email protected]>
---
 libavcodec/shorten.c | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)

diff --git a/libavcodec/shorten.c b/libavcodec/shorten.c
index c0325a81f8..d1f4fcffa9 100644
--- a/libavcodec/shorten.c
+++ b/libavcodec/shorten.c
@@ -564,6 +564,12 @@ static int shorten_decode_frame(AVCodecContext *avctx, AVFrame *frame,
     buf_size         += s->bitstream_size;
     s->bitstream_size = buf_size;
 
+    /* During draining, if no buffered data remains, return EOF. */
+    if (!avpkt->data && !buf_size) {
+        *got_frame_ptr = 0;
+        return 0;
+    }
+
     /* do not decode until buffer has at least max_framesize bytes or
      * the end of the file has been reached */
     if (buf_size < s->max_framesize && avpkt->data) {
@@ -580,6 +586,10 @@ static int shorten_decode_frame(AVCodecContext *avctx, AVFrame *frame,
 
         if ((ret = read_header(s)) < 0)
             return ret;
+        /* Validate audio parameters so uninitialized extradata fails cleanly
+         * with AVERROR_INVALIDDATA instead of emitting an invalid frame. */
+        if (avctx->sample_rate <= 0 || !av_channel_layout_check(&avctx->ch_layout))
+            return AVERROR_INVALIDDATA;
 
         if (avpkt->size) {
             int max_framesize = s->blocksize * s->channels * 8;
@@ -774,6 +784,14 @@ static int shorten_decode_frame(AVCodecContext *avctx, AVFrame *frame,
 
 finish_frame:
     s->bitindex = get_bits_count(&s->gb) - 8 * (get_bits_count(&s->gb) / 8);
+    /* During draining, if no frame was produced, the remaining buffer is
+     * unparseable stale data. Clear it so the next drain call returns EOF
+     * instead of retrying the same bytes in an infinite loop. */
+    if (!avpkt->data && !*got_frame_ptr) {
+        s->bitstream_size  = 0;
+        s->bitstream_index = 0;
+        return 0;
+    }
     i           = get_bits_count(&s->gb) / 8;
     if (i > buf_size) {
         av_log(s->avctx, AV_LOG_ERROR, "overread: %d\n", i - buf_size);
-- 
2.52.0

_______________________________________________
ffmpeg-devel mailing list -- [email protected]
To unsubscribe send an email to [email protected]
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.