PR #25574 opened by Romain Beauxis (toots) URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/25574 Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/25574.patch
Header packets of a chained stream are only buffered in identification, comment, setup order. A misplaced packet discards the buffered set, so a missing or misordered header no longer mixes headers from different chains into the new extradata. >From b1cfc30c130baf471ec39c1051f1911527256bf9 Mon Sep 17 00:00:00 2001 From: Romain Beauxis <[email protected]> Date: Wed, 28 Oct 2026 16:33:52 -0500 Subject: [PATCH] avformat/oggparsevorbis: enforce header order in chained streams Header packets of a chained stream are only buffered in identification, comment, setup order. A misplaced packet discards the buffered set, so a missing or misordered header no longer mixes headers from different chains into the new extradata. --- libavformat/oggparsevorbis.c | 65 ++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/libavformat/oggparsevorbis.c b/libavformat/oggparsevorbis.c index 5a23fc44502..82f5aa23beb 100644 --- a/libavformat/oggparsevorbis.c +++ b/libavformat/oggparsevorbis.c @@ -209,9 +209,17 @@ int ff_vorbis_comment(AVFormatContext *as, AVDictionary **m, * [framing_flag] = read one bit | Not Used */ +enum VorbisPacketType { + VORBIS_PACKET_DATA, + VORBIS_PACKET_ID, + VORBIS_PACKET_COMMENT, + VORBIS_PACKET_SETUP, +}; + struct oggvorbis_private { unsigned int len[3]; unsigned char *packet[3]; + enum VorbisPacketType last_packet; ///< type of the last packet seen by vorbis_packet() AVVorbisParseContext *vp; int64_t bos_page_pos; int ts_offset; @@ -445,6 +453,53 @@ static int vorbis_header(AVFormatContext *s, int idx) return 1; } +/** + * Check that a packet follows the identification, comment, setup order of a + * chained stream's headers, and record it as the last packet. + * + * An identification header starts a new set. A misplaced packet discards the + * buffered headers, so an incomplete or misordered set is never packed. + * + * @return 0 if the packet is in order, AVERROR_INVALIDDATA otherwise + */ +static int vorbis_check_packet_order(AVFormatContext *s, + struct oggvorbis_private *priv, + enum VorbisPacketType type) +{ + enum VorbisPacketType last = priv->last_packet; + const char *error = NULL; + + switch (type) { + case VORBIS_PACKET_DATA: + if (last == VORBIS_PACKET_ID || last == VORBIS_PACKET_COMMENT) + error = "data packet before the setup header"; + break; + case VORBIS_PACKET_ID: + if (last == VORBIS_PACKET_ID || last == VORBIS_PACKET_COMMENT) + error = "identification header before the setup header"; + break; + case VORBIS_PACKET_COMMENT: + if (last != VORBIS_PACKET_ID) + error = "comment header without identification header"; + break; + case VORBIS_PACKET_SETUP: + if (last != VORBIS_PACKET_COMMENT) + error = "setup header without comment header"; + break; + } + + if (error) + av_log(s, AV_LOG_WARNING, + "Invalid chained stream headers: %s, discarding them\n", error); + + if (error || type == VORBIS_PACKET_ID) + for (int i = 0; i < 3; i++) + av_freep(&priv->packet[i]); + + priv->last_packet = error && type != VORBIS_PACKET_ID ? VORBIS_PACKET_DATA : type; + return error ? AVERROR_INVALIDDATA : 0; +} + static int vorbis_packet(AVFormatContext *s, int idx) { struct ogg *ogg = s->priv_data; @@ -553,6 +608,8 @@ static int vorbis_packet(AVFormatContext *s, int idx) * skipped; the headers are buffered and attached as extradata to the * first data packet that follows. */ if (flags & VORBIS_FLAG_HEADER) { + vorbis_check_packet_order(s, priv, VORBIS_PACKET_ID); + ret = vorbis_parse_header(s, s->streams[idx], os->buf + os->pstart, os->psize); if (ret < 0) return ret; @@ -572,6 +629,9 @@ static int vorbis_packet(AVFormatContext *s, int idx) if (ret < 0) return ret; + if (vorbis_check_packet_order(s, priv, VORBIS_PACKET_COMMENT) < 0) + return 1; + ret = av_reallocp(&priv->packet[1], os->psize); if (ret < 0) return ret; @@ -584,6 +644,9 @@ static int vorbis_packet(AVFormatContext *s, int idx) } if (flags & VORBIS_FLAG_SETUP) { + if (vorbis_check_packet_order(s, priv, VORBIS_PACKET_SETUP) < 0) + return 1; + ret = av_reallocp(&priv->packet[2], os->psize); if (ret < 0) return ret; @@ -594,6 +657,8 @@ static int vorbis_packet(AVFormatContext *s, int idx) skip_packet = 1; } + if (!skip_packet) + vorbis_check_packet_order(s, priv, VORBIS_PACKET_DATA); /* All three headers for the new chained stream have been collected; * pack them into new extradata to be attached to the next data packet. */ -- 2.54.0 _______________________________________________ ffmpeg-devel mailing list -- [email protected] To unsubscribe send an email to [email protected]
