Commit a6e9b539f7 for ffmpeg
commit a6e9b539f7af80690a4cf5cc98ce4f72b8fd270d
Author: Michael Niedermayer <michael@niedermayer.cc>
Date: Sun Nov 1 14:34:12 2026 +0100
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. The
RTP QuickTime payload parser builds its own MOVContext for the sample
description it receives, so it has to set up the same state.
Fixes: heap-buffer-overflow in libopus_decode()
Fixes: mov/esds-outside-trak.mp4
Fixes: JWOFdec1AfGI
Fixes: #24931
Reported-by: Thomas Guilbert <tguilbert@chromium.org>
diff --git a/libavformat/mov.c b/libavformat/mov.c
index c62d4fe239..edab98a037 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);
}
@@ -1361,9 +1369,9 @@ static int mov_read_wfex(MOVContext *c, AVIOContext *pb, MOVAtom atom)
AVStream *st;
int ret;
- if (c->fc->nb_streams < 1)
+ st = get_curr_st(c);
+ if (!st)
return 0;
- st = c->fc->streams[c->fc->nb_streams-1];
if ((ret = ff_get_wav_header(c->fc, pb, st->codecpar, atom.size, 0)) < 0)
av_log(c->fc, AV_LOG_WARNING, "get_wav_header failed\n");
@@ -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)
- return AVERROR_INVALIDDATA;
-
- st = fc->streams[fc->nb_streams - 1];
+ st = get_curr_st(c);
+ if (!st)
+ return 0;
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;
@@ -2726,7 +2732,7 @@ static int mov_read_cdsc_rndr(MOVContext* c, AVIOContext* pb, MOVAtom atom)
st = get_curr_st(c);
if (!st)
- return AVERROR_INVALIDDATA;
+ return 0;
sc = st->priv_data;
MovTref *tag = mov_add_tref_tag(sc, atom.type);
@@ -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) {
@@ -7911,9 +7917,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)
diff --git a/libavformat/rtpdec_qt.c b/libavformat/rtpdec_qt.c
index af00a7e767..ce149d9723 100644
--- a/libavformat/rtpdec_qt.c
+++ b/libavformat/rtpdec_qt.c
@@ -146,6 +146,8 @@ static int qt_rtp_parse_packet(AVFormatContext *s, PayloadContext *qt,
if (!mc)
return AVERROR(ENOMEM);
mc->fc = s;
+ mc->cur_item_id = -1;
+ mc->trak_index = st->index;
st->priv_data = msc = av_mallocz(sizeof(MOVStreamContext));
if (!msc) {
av_free(mc);