[PR] fix/24290-vpk-div0 (PR #24297)

Jun Zhao via ffmpeg-devel <[email protected]>
Newsgroups gmane.comp.video.ffmpeg.devel
Message-ID <[email protected]>
PR #24297 opened by Jun Zhao (mypopydev)
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/24297
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/24297.patch

These three commits fix #24290: avformat_find_stream_info() no longer overwrites a container channel layout with the empty layout left behind by a failed decoder open; VPK rechecks the channel count before dividing in the last block; and a generated 21-byte FATE sample checks that the dump still reports 80 channels.


From c424945cf51b7a49365e2c93d710a200bea82c51 Mon Sep 17 00:00:00 2001
From: Jun Zhao <[email protected]>
Date: Fri, 28 Aug 2026 07:44:27 +0800
Subject: [PATCH 1/3] avformat: Restore the container channel layout after a
 failed decoder open
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

avformat_find_stream_info() copies codec parameters from the decoder
context after probing, including when avcodec_open2() has already
failed. A failed avcodec_open2() zeroes the context channel layout via
ff_codec_close() -> av_opt_free(), because ch_layout is an
AV_OPT_TYPE_CHLAYOUT option. That empty layout is then written back
onto codecpar and replaces the value the demuxer had already set from
the container.

This is reachable for codecs such as adpcm_psx that have no parser and
do not set AVSTREAM_PARSE_*: the only source of the channel count is
the demuxer header. It differs from codecs like mp3, where the decoder
is expected to fill the layout.

Restore the container channel layout when it was specified and the
decoder result is unspecified, matching the existing restore of color
metadata in parameters_from_context().

See also:
https://ffmpeg.org/pipermail/ffmpeg-devel/2024-November/335598.html

Fixes: #24290
Fixes: https://issues.oss-fuzz.com/issues/42536474
Reported-by: Darío Clavijo
Found-by: OSS-Fuzz
Signed-off-by: Jun Zhao <[email protected]>
---
 libavformat/demux.c | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/libavformat/demux.c b/libavformat/demux.c
index 193fd17739..99029d4221 100644
--- a/libavformat/demux.c
+++ b/libavformat/demux.c
@@ -2597,6 +2597,16 @@ static int parameters_from_context(AVFormatContext *ic, AVCodecParameters *par,
     if (par_tmp->chroma_location != AVCHROMA_LOC_UNSPECIFIED)
         par->chroma_location = par_tmp->chroma_location;
 
+    /* A failed avcodec_open2() zeroes ch_layout through
+     * ff_codec_close() -> av_opt_free(); do not copy that empty layout
+     * over a container-signaled one. Other AVOption types used here are
+     * integers and are not cleared. */
+    if (par_tmp->ch_layout.nb_channels > 0 && !par->ch_layout.nb_channels) {
+        ret = av_channel_layout_copy(&par->ch_layout, &par_tmp->ch_layout);
+        if (ret < 0)
+            goto fail;
+    }
+
     ret = 0;
 fail:
     avcodec_parameters_free(&par_tmp);
-- 
2.52.0


From 2227122b931708875d5ba866354939eb729014a0 Mon Sep 17 00:00:00 2001
From: Jun Zhao <[email protected]>
Date: Fri, 28 Aug 2026 07:44:27 +0800
Subject: [PATCH 2/3] avformat/vpk: Check the channel count before dividing in
 the last block
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

vpk_read_packet() divides last_block_size and block_align by
codecpar->ch_layout.nb_channels when assembling the last interleaved
block. Header parsing already rejects a non-positive channel count,
but a failed avcodec_open2() can later zero the layout through
ff_codec_close() -> av_opt_free(), so the division is reached with a
zero divisor.

Check the channel count again before dividing and return
AVERROR_INVALIDDATA.

Original-patch-by: Kacper Michajłow <[email protected]>
Fixes: #24290
Reported-by: Darío Clavijo
Found-by: OSS-Fuzz
Signed-off-by: Jun Zhao <[email protected]>
---
 libavformat/vpk.c | 11 ++++++++---
 1 file changed, 8 insertions(+), 3 deletions(-)

diff --git a/libavformat/vpk.c b/libavformat/vpk.c
index f6270a11ae..172e45d7da 100644
--- a/libavformat/vpk.c
+++ b/libavformat/vpk.c
@@ -87,9 +87,14 @@ static int vpk_read_packet(AVFormatContext *s, AVPacket *pkt)
 
     vpk->current_block++;
     if (vpk->current_block == vpk->block_count) {
-        unsigned size = vpk->last_block_size / par->ch_layout.nb_channels;
-        unsigned skip = (par->block_align - vpk->last_block_size) / par->ch_layout.nb_channels;
-        uint64_t pos = avio_tell(s->pb);
+        unsigned size, skip;
+        uint64_t pos;
+
+        if (par->ch_layout.nb_channels <= 0)
+            return AVERROR_INVALIDDATA;
+        size = vpk->last_block_size / par->ch_layout.nb_channels;
+        skip = (par->block_align - vpk->last_block_size) / par->ch_layout.nb_channels;
+        pos = avio_tell(s->pb);
 
         ret = av_new_packet(pkt, vpk->last_block_size);
         if (ret < 0)
-- 
2.52.0


From 7af4b6c67fedd2584e44f254dbef9d46fa7da685 Mon Sep 17 00:00:00 2001
From: Jun Zhao <[email protected]>
Date: Fri, 28 Aug 2026 07:44:27 +0800
Subject: [PATCH 3/3] tests/fate: Add a VPK regression test for a zeroed
 channel layout

Generate the 21-byte sample from issue #24290 and copy it with
ffmpeg. avformat_find_stream_info() must keep the container channel
count at 80 instead of replacing it with 0 after adpcm_psx fails to
open; the decoder cannot be opened, so ffprobe -show_entries is not
usable here.

Signed-off-by: Jun Zhao <[email protected]>
---
 tests/fate/demux.mak | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/tests/fate/demux.mak b/tests/fate/demux.mak
index 4cdc1a583f..b02f0d5010 100644
--- a/tests/fate/demux.mak
+++ b/tests/fate/demux.mak
@@ -189,6 +189,20 @@ fate-ts-timed-id3-hls-demux: CMD = ffprobe_demux $(TARGET_PATH)/tests/data/id3.m
 FATE_SAMPLES_DEMUX-$(call PARSERDEM, JPEGXS, IMAGE_JPEGXS_PIPE, CONCAT_PROTOCOL) += fate-jxs-concat-demux
 fate-jxs-concat-demux: CMD = framecrc "-i concat:$(TARGET_SAMPLES)/jxs/lena.jxs|$(TARGET_SAMPLES)/jxs/lena.jxs -c:v copy"
 
+# 21-byte crafted VPK: header parses (nb_channels=80) but adpcm_psx open
+# fails. After find_stream_info the layout must stay 80, not 0.
+# ffprobe cannot be used: it aborts on the failed decoder open before
+# printing -show_entries.
+tests/data/vpk-div0.vpk: TAG = GEN
+tests/data/vpk-div0.vpk: | tests/data
+	$(Q)printf '\040\113\120\126\126\120\000\370\004\000\073\003\141\071\126\062\066\066\060\070\120' > $@
+
+FATE_FFMPEG-$(call ALLYES, VPK_DEMUXER ADPCM_PSX_DECODER FILE_PROTOCOL NULL_MUXER) += fate-demux-vpk-div0
+fate-demux-vpk-div0: tests/data/vpk-div0.vpk
+fate-demux-vpk-div0: CMD = ffmpeg -i $(TARGET_PATH)/tests/data/vpk-div0.vpk -map 0 -c copy -f null -
+fate-demux-vpk-div0: CMP = grep
+fate-demux-vpk-div0: REF = 80 channels
+
 FATE_SAMPLES_DEMUX += $(FATE_SAMPLES_DEMUX-yes)
 FATE_SAMPLES_FFMPEG += $(FATE_SAMPLES_DEMUX)
 FATE_FFPROBE_DEMUX   += $(FATE_FFPROBE_DEMUX-yes)
-- 
2.52.0

_______________________________________________
ffmpeg-devel mailing list -- [email protected]
To unsubscribe send an email to [email protected]
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.