[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]