PR #24931 opened by tguilbert-google URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/24931 Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/24931.patch
# Summary of changes This fixes a heap buffer overflow in `libopus_decode()`. If a demuxer changes a stream's codec ID during `avformat_find_stream_info()`, the new codec's parser runs on the context of the still-open decoder, and can shrink the channel count used to size the output buffer. The first commit closes the decoder and parser when the codec ID changes. The second makes the libopus wrapper refuse to decode if the channel count or sample format changed since init. >From bcddef7158cdb31766fafa3eb24a6b5726f141f2 Mon Sep 17 00:00:00 2001 From: Thomas Guilbert <[email protected]> Date: Mon, 5 Oct 2026 21:32:05 +0000 Subject: [PATCH 1/2] avformat/demux: Update the context when the codec ID changes Demuxers can change `codecpar->codec_id` without setting `need_context_update`, e.g. mov with a top-level `esds` box. The new codec's parser then runs on the context of the still-open decoder, and can change the channel count used to size its output buffers. This commit treats a codec ID mismatch on an open decoder as a context update. Fixes: heap-buffer-overflow in opus_copy_channel_out_short --- libavformat/demux.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/libavformat/demux.c b/libavformat/demux.c index 97eaa5f9bc..6be8fdc2d9 100644 --- a/libavformat/demux.c +++ b/libavformat/demux.c @@ -1423,6 +1423,13 @@ static int read_frame_internal(AVFormatContext *s, AVPacket *pkt) if (new_extradata) sti->need_context_update = 1; + /* Some demuxers change codecpar->codec_id without requesting a + * context update. Treat it as one, so that we never run a parser or + * decoder for one codec on a context opened for another. */ + if (avcodec_is_open(sti->avctx) && + sti->avctx->codec_id != st->codecpar->codec_id) + sti->need_context_update = 1; + /* update context if required */ if (sti->need_context_update) { if (avcodec_is_open(sti->avctx)) { -- 2.52.0 >From 44a16452f039e9bcf33dca53c7835bdac6507596 Mon Sep 17 00:00:00 2001 From: Thomas Guilbert <[email protected]> Date: Mon, 5 Oct 2026 21:33:14 +0000 Subject: [PATCH 2/2] avcodec/libopusdec: Check the output parameters before decoding `libopus_decode()` sizes its output buffer from `avc`, but libopus writes as many channels as it was created with. This commit refuses to decode if the channel count or sample format changed since init. Fixes: heap-buffer-overflow in opus_copy_channel_out_short --- libavcodec/libopusdec.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/libavcodec/libopusdec.c b/libavcodec/libopusdec.c index fc2119baff..6721694802 100644 --- a/libavcodec/libopusdec.c +++ b/libavcodec/libopusdec.c @@ -39,6 +39,8 @@ struct libopus_context { AVClass *class; OpusMSDecoder *dec; int pre_skip; + int channels; + enum AVSampleFormat sample_fmt; #ifndef OPUS_SET_GAIN union { int i; double d; } gain; #endif @@ -113,6 +115,8 @@ static av_cold int libopus_decode_init(AVCodecContext *avc) opus_strerror(ret)); return ff_opus_error_to_averror(ret); } + opus->channels = channels; + opus->sample_fmt = avc->sample_fmt; #ifdef OPUS_SET_GAIN ret = opus_multistream_decoder_ctl(opus->dec, OPUS_SET_GAIN(gain_db)); @@ -163,6 +167,15 @@ static int libopus_decode(AVCodecContext *avc, AVFrame *frame, struct libopus_context *opus = avc->priv_data; int ret, nb_samples; + /* The output buffer is sized from avc, but libopus writes interleaved + * samples for as many channels as the decoder was created with. */ + if (avc->ch_layout.nb_channels != opus->channels || + avc->sample_fmt != opus->sample_fmt) { + av_log(avc, AV_LOG_ERROR, + "Channel count or sample format changed since init.\n"); + return AVERROR(EINVAL); + } + frame->nb_samples = MAX_FRAME_SIZE; if ((ret = ff_get_buffer(avc, frame, 0)) < 0) return ret; -- 2.52.0 _______________________________________________ ffmpeg-devel mailing list -- [email protected] To unsubscribe send an email to [email protected]
