[PR] avfilter/af_pan: check named input channel ids before use (PR #24004)
iSoldLeo via ffmpeg-devel <[email protected]> Tue, 04 Aug 2026 12:18:02 -0000
| Newsgroups | gmane.comp.video.ffmpeg.devel |
|---|---|
| Message-ID | <178584588339.59.13335218697373102776@29965ddac10e> |
PR #24004 opened by iSoldLeo URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/24004 Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/24004.patch Named input channels are parsed to sparse AVChannel values and then used directly as indices into 64-element arrays. Values such as UNSD, UNK and AMBI can therefore cause out-of-bounds accesses. Reject unsupported ids before the first array access. Keep the check in the input path because high channel ids on the output side are valid after conversion to layout indices. Add a FATE test that checks for the specific diagnostic, so a crash cannot be mistaken for the expected rejection. Fixes #22963. Tested on an Apple M4 Mac: - native and sanitizer builds - all fate-filter-pan-* tests - valid and invalid named and numbered channel cases >From 9cb1c0fe734ec3386c2a3f24f50465adca6f3e44 Mon Sep 17 00:00:00 2001 From: iSold Leo <[email protected]> Date: Tue, 4 Aug 2026 19:50:11 +0800 Subject: [PATCH 1/2] avfilter/af_pan: check the id of named input channels before use parse_channel_name() only rejects negative values on the named channel path, while the numbered "c%d" path also checks against MAX_CHANNELS. av_channel_from_string() accepts UNSD (512), UNK (768) and AMBI (1024), and the id was then used directly to index used_in_ch[MAX_CHANNELS] on the stack and pan->gain[out_ch_id][in_ch_id]. Before this change: ffmpeg -f lavfi -i "anullsrc=cl=stereo" -af "pan=stereo|FL=AMBI" -f null - af_pan.c:214:17: runtime error: index 1024 out of bounds for type 'int[64]' The first out of bounds access is the read at the "reference twice" check, so the symptom depends on what happens to be on the stack: FL=UNK is silently accepted and produces silence, FL=UNSD reports "Can not reference in channel 512 twice", and FL=AMBI aborts. The check has to be at the caller and not in parse_channel_name(), which is shared with the out channel path: there the named id is converted by av_channel_layout_index_from_channel() into a layout index, so high ids are legitimately supported and "pan=AMBI|AMBI=FL" works. AVERROR_PATCHWELCOME is used because these are valid AVChannel values that af_pan cannot represent: for named input channels the gain matrix is indexed by the raw id, and the renumbering loop in config_props() is bounded by MAX_CHANNELS as well, so such a mapping never worked. The in_ch_id < 0 half is currently unreachable and only kept for symmetry with the out channel check above. Regression since 1f96db959c1235bb7079d354e09914a0a2608f62, which dropped the "channel_id >= MAX_CHANNELS" part of the check when converting to the new channel layout API. Fixes: #22963 --- libavfilter/af_pan.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/libavfilter/af_pan.c b/libavfilter/af_pan.c index 32bd28fe0a..abb0e5804d 100644 --- a/libavfilter/af_pan.c +++ b/libavfilter/af_pan.c @@ -211,6 +211,12 @@ static av_cold int init(AVFilterContext *ctx) ret = AVERROR(EINVAL); goto fail; } + if (in_ch_id < 0 || in_ch_id >= MAX_CHANNELS) { + av_log(ctx, AV_LOG_ERROR, + "Input channel id %d is not supported\n", in_ch_id); + ret = AVERROR_PATCHWELCOME; + goto fail; + } if (used_in_ch[in_ch_id]) { av_log(ctx, AV_LOG_ERROR, "Can not reference in channel %d twice\n", in_ch_id); -- 2.52.0 >From 00b019289c53f939b28a8e466a77066f9c24c69d Mon Sep 17 00:00:00 2001 From: iSold Leo <[email protected]> Date: Tue, 4 Aug 2026 19:50:11 +0800 Subject: [PATCH 2/2] fate/filter-audio: add test for pan named input channel id rejection "pan=stereo|FL=UNK" resolves to AVChannel id 768, which was used as an index into a 64 element array before the previous commit. UNK is used because it was the only one of the three reachable high ids that exited with 0 before the fix; AMBI (1024) aborted and UNSD (512) failed with an unrelated message, so a test that only checked for a non-zero exit status would have passed before the fix as well. For the same reason the test greps the error message on stderr instead of only looking at the exit status: a crash also exits non-zero. --- tests/fate/filter-audio.mak | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/fate/filter-audio.mak b/tests/fate/filter-audio.mak index 7817548037..6593750805 100644 --- a/tests/fate/filter-audio.mak +++ b/tests/fate/filter-audio.mak @@ -191,6 +191,11 @@ fate-filter-pan-downmix2: tests/data/asynth-44100-11.wav fate-filter-pan-downmix2: SRC = $(TARGET_PATH)/tests/data/asynth-44100-11.wav fate-filter-pan-downmix2: CMD = framecrc -ss 3.14 -i $(SRC) -frames:a 20 -filter:a "pan=5C|c0=0.7*c0+0.7*c10|c1=c9|c2=c8|c3=c7|c4=c6" +FATE_AFILTER-$(call ALLYES, LAVFI_INDEV ANULLSRC_FILTER PAN_FILTER PCM_S16LE_ENCODER NULL_MUXER) += fate-filter-pan-channel-id-limit +fate-filter-pan-channel-id-limit: CMD = run $(FFMPEG) -nostdin -hide_banner -f lavfi -i "anullsrc=cl=stereo:r=44100:d=0.1" -af "pan=stereo|FL=UNK" -f null - ; true +fate-filter-pan-channel-id-limit: CMP = grep +fate-filter-pan-channel-id-limit: REF = Input channel id 768 + FATE_AFILTER-$(call ALLYES, LAVFI_INDEV AEVALSRC_FILTER SILENCEREMOVE_FILTER ARESAMPLE_FILTER) += fate-filter-silenceremove fate-filter-silenceremove: CMD = framecrc -auto_conversion_filters -f lavfi -i "aevalsrc=between(t\,1\,2)+between(t\,4\,5)+between(t\,7\,9):d=10:n=8192,silenceremove=start_periods=0:start_duration=0:start_threshold=0:stop_periods=-1:stop_duration=0:stop_threshold=-90dB:window=0:detection=avg" -- 2.52.0 _______________________________________________ ffmpeg-devel mailing list -- [email protected] To unsubscribe send an email to [email protected]