[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]