PR #25671 opened by michaelni URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/25671 Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/25671.patch
Make get_curr_st() return NULL when neither a trak nor a HEIF item is being parsed, and use it in the readers that rewrite the codec id. Fixes: heap-buffer-overflow in libopus_decode() Fixes: mov/esds-outside-trak.mp4 Fixes: JWOFdec1AfGI Fixes: #24931 Reported-by: Thomas Guilbert <[email protected]> >From e656240e28b4811001d30871c771907cc29c8687 Mon Sep 17 00:00:00 2001 From: Michael Niedermayer <[email protected]> Date: Sun, 1 Nov 2026 14:34:12 +0100 Subject: [PATCH 1/2] avformat/mov: ignore sample description atoms outside a trak Make get_curr_st() return NULL when neither a trak nor a HEIF item is being parsed, and use it in the readers that rewrite the codec id. Fixes: heap-buffer-overflow in libopus_decode() Fixes: mov/esds-outside-trak.mp4 Fixes: JWOFdec1AfGI Fixes: #24931 Reported-by: Thomas Guilbert <[email protected]> --- libavformat/mov.c | 36 +++++++++++++++++++++--------------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/libavformat/mov.c b/libavformat/mov.c index 786994699e7..8c4b459940c 100644 --- a/libavformat/mov.c +++ b/libavformat/mov.c @@ -212,7 +212,8 @@ static HEIFItem *get_heif_item(MOVContext *c, unsigned id) /** * Get the current stream in the parsing process. This can either be the - * latest stream added to the context, or the stream referenced by an item. + * stream of the trak being parsed, or the stream referenced by an item. + * Returns NULL when neither a trak nor an item is being parsed. */ static AVStream *get_curr_st(MOVContext *c) { @@ -222,8 +223,13 @@ static AVStream *get_curr_st(MOVContext *c) if (c->fc->nb_streams < 1) return NULL; - if (c->cur_item_id == -1) + if (c->cur_item_id == -1) { + if (c->trak_index < 0) { + av_log(c->fc, AV_LOG_WARNING, "Sample description atom outside TRAK\n"); + return NULL; + } return c->fc->streams[c->fc->nb_streams-1]; + } item = get_heif_item(c, c->cur_item_id); if (item) @@ -865,6 +871,8 @@ static int mov_read_hdlr(MOVContext *c, AVIOContext *pb, MOVAtom atom) static int mov_read_esds(MOVContext *c, AVIOContext *pb, MOVAtom atom) { + if (!get_curr_st(c)) + return 0; return ff_mov_read_esds(c->fc, pb); } @@ -2093,13 +2101,12 @@ static int mov_read_mvhd(MOVContext *c, AVIOContext *pb, MOVAtom atom) return 0; } -static void set_last_stream_little_endian(AVFormatContext *fc) +static void set_curr_stream_little_endian(MOVContext *c) { - AVStream *st; + AVStream *st = get_curr_st(c); - if (fc->nb_streams < 1) + if (!st) return; - st = fc->streams[fc->nb_streams-1]; switch (st->codecpar->codec_id) { case AV_CODEC_ID_PCM_S16BE: @@ -2127,7 +2134,7 @@ static int mov_read_enda(MOVContext *c, AVIOContext *pb, MOVAtom atom) int little_endian = avio_rb16(pb) & 0xFF; av_log(c->fc, AV_LOG_TRACE, "enda %d\n", little_endian); if (little_endian == 1) - set_last_stream_little_endian(c->fc); + set_curr_stream_little_endian(c); return 0; } @@ -2158,10 +2165,9 @@ static int mov_read_pcmc(MOVContext *c, AVIOContext *pb, MOVAtom atom) format_flags = avio_r8(pb); pcm_sample_size = avio_r8(pb); - if (fc->nb_streams < 1) + st = get_curr_st(c); + if (!st) return AVERROR_INVALIDDATA; - - st = fc->streams[fc->nb_streams - 1]; sc = st->priv_data; if (sc->format == MOV_MP4_FPCM_TAG) { @@ -2202,7 +2208,7 @@ static int mov_read_pcmc(MOVContext *c, AVIOContext *pb, MOVAtom atom) } if (format_flags & 1) // indicates little-endian format. If not present, big-endian format is used - set_last_stream_little_endian(c->fc); + set_curr_stream_little_endian(c); st->codecpar->bits_per_coded_sample = av_get_bits_per_sample(st->codecpar->codec_id); return 0; @@ -3477,9 +3483,9 @@ static int mov_read_stsd(MOVContext *c, AVIOContext *pb, MOVAtom atom) MOVStreamContext *sc; int ret, entries; - if (c->fc->nb_streams < 1) + st = get_curr_st(c); + if (!st) return 0; - st = c->fc->streams[c->fc->nb_streams - 1]; sc = st->priv_data; if (sc->extradata) { @@ -7907,9 +7913,9 @@ static int mov_read_frma(MOVContext *c, AVIOContext *pb, MOVAtom atom) enum AVCodecID id; AVStream *st; - if (c->fc->nb_streams < 1) + st = get_curr_st(c); + if (!st) return 0; - st = c->fc->streams[c->fc->nb_streams - 1]; sc = st->priv_data; switch (sc->format) -- 2.54.0 >From 104bd435247b37693f8d4d2beaee2027343ca4fe Mon Sep 17 00:00:00 2001 From: Michael Niedermayer <[email protected]> Date: Sun, 1 Nov 2026 14:34:12 +0100 Subject: [PATCH 2/2] avformat/demux: pick the replacement probe decoder like try_decode_frame() codec_close() allocates the new context for the decoder returned by avcodec_find_decoder(), while try_decode_frame() reopens it with find_probe_decoder(), which honours the decoder forced through AVFormatContext.audio_codec and friends as well as the h264 special case. When the two differ, avcodec_open2() rejects the context as allocated for another decoder and the stream is not probed further. --- libavformat/demux.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/libavformat/demux.c b/libavformat/demux.c index 359ae2612bc..1468726b096 100644 --- a/libavformat/demux.c +++ b/libavformat/demux.c @@ -186,7 +186,7 @@ static int init_input(AVFormatContext *s, const char *filename, s, 0, s->format_probesize); } -static int codec_close(FFStream *sti); +static int codec_close(AVFormatContext *s, FFStream *sti); static int update_stream_avctx(AVFormatContext *s) { @@ -200,7 +200,7 @@ static int update_stream_avctx(AVFormatContext *s) if (avcodec_is_open(sti->avctx)) { av_log(s, AV_LOG_DEBUG, "Demuxer context update while decoder is open, closing and trying to re-open\n"); - ret = codec_close(sti); + ret = codec_close(s, sti); sti->info->found_decoder = 0; if (ret < 0) return ret; @@ -1360,7 +1360,7 @@ static int64_t ts_to_samples(AVStream *st, int64_t ts) return av_rescale(ts, st->time_base.num * st->codecpar->sample_rate, st->time_base.den); } -static int codec_close(FFStream *sti) +static int codec_close(AVFormatContext *s, FFStream *sti) { AVCodecContext *avctx_new = NULL; AVCodecParameters *par_tmp = NULL; @@ -1369,7 +1369,7 @@ static int codec_close(FFStream *sti) new_codec = (sti->avctx->codec_id != sti->pub.codecpar->codec_id) ? - avcodec_find_decoder(sti->pub.codecpar->codec_id) : + find_probe_decoder(s, &sti->pub, sti->pub.codecpar->codec_id) : sti->avctx->codec; avctx_new = avcodec_alloc_context3(new_codec); @@ -1451,7 +1451,7 @@ static int read_frame_internal(AVFormatContext *s, AVPacket *pkt) if (sti->need_context_update) { if (avcodec_is_open(sti->avctx)) { av_log(s, AV_LOG_DEBUG, "Demuxer context update while decoder is open, closing and trying to re-open\n"); - ret = codec_close(sti); + ret = codec_close(s, sti); sti->info->found_decoder = 0; if (ret < 0) return ret; @@ -3274,7 +3274,7 @@ find_stream_info_err: } if (avcodec_is_open(sti->avctx)) { - err = codec_close(sti); + err = codec_close(ic, sti); if (err < 0 && ret >= 0) ret = err; } -- 2.54.0 _______________________________________________ ffmpeg-devel mailing list -- [email protected] To unsubscribe send an email to [email protected]
