[PR] avfilter/avf_showspectrum: fix out-of-bounds read in separate mode (PR #23920)
akx via ffmpeg-devel <[email protected]> Sun, 26 Jul 2026 17:20:12 -0000
| Newsgroups | gmane.comp.video.ffmpeg.devel |
|---|---|
| Message-ID | <178508645541.59.10451612104938261266@29965ddac10e> |
PR #23920 opened by akx URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/23920 Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/23920.patch # Summary of changes This fixes an out-of-bounds read in showspectrum, found and fixed by Claude Opus 5 during implementation of other showspectrum-related things. The access is a read, so nothing is corrupted, and it does not fault under the system allocator. Under a guard page allocator it segfaults. No heap contents reach the picture, either. See the commit message for full details. A crash (SIGSEGV under GuardMalloc) is easily reproduced with e.g. on my macOS machine with ``` env DYLD_INSERT_LIBRARIES=/usr/lib/libgmalloc.dylib MALLOC_FILL_SPACE=1 ffmpeg -f lavfi -i "sine=d=8,aformat=channel_layouts=5.1" -filter_complex showspectrumpic=s=1024x512:mode=separate -frames:v 1 out.png ``` >From c8e6acacf43bb0e5283d19da80ec4dec4f7ed252 Mon Sep 17 00:00:00 2001 From: Aarni Koskela <[email protected]> Date: Sun, 26 Jul 2026 19:32:16 +0300 Subject: [PATCH] avfilter/avf_showspectrum: fix out-of-bounds read in separate mode config_output() derives the FFT size from the per channel dimension, so fft_data[] holds about channel_height entries in a vertical layout and about channel_width in a horizontal one. The four functions that turn the transform into magnitudes and phases instead iterate over the full s->h or s->w and index fft_data[] with it, reading past the end whenever that dimension exceeds the allocated buf_size. With 5.1 and s=1024x512, channel_height is 512 / 6 = 85, so fft_data[] is allocated for 176 entries while the loops read 512 of them, running 2688 bytes past a 1408 byte allocation: ffmpeg -f lavfi -i "sine=d=8,aformat=channel_layouts=5.1" \ -filter_complex showspectrumpic=s=1024x512:mode=separate \ -frames:v 1 out.png Three or more channels overflow at any size. Two channels overflow only where halving the dimension truncates and the alignment does not round back up, such as s=1024x513 or s=1025x512 with a 16 byte alignment. Bound the loops by channel_height and channel_width, as the plotting functions already are. Those functions never read past the channel dimension, so the entries in question were computed and then discarded: no output changes, and no heap contents reach the picture. This was verified over channel counts, layouts and orientations against the previous behaviour. The access is a read, so nothing is corrupted, and it does not fault under the system allocator. Under a guard page allocator it segfaults. Found with AddressSanitizer. Affects showspectrum and showspectrumpic. Co-Authored-By: Claude Opus 5 (1M context) <[email protected]> --- libavfilter/avf_showspectrum.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libavfilter/avf_showspectrum.c b/libavfilter/avf_showspectrum.c index 0345b4458d..ee52136ce7 100644 --- a/libavfilter/avf_showspectrum.c +++ b/libavfilter/avf_showspectrum.c @@ -1310,7 +1310,7 @@ static int calc_channel_magnitudes(AVFilterContext *ctx, void *arg, int jobnr, i { ShowSpectrumContext *s = ctx->priv; const double w = s->win_scale * (s->scale == LOG ? s->win_scale : 1); - int y, h = s->orientation == VERTICAL ? s->h : s->w; + int y, h = s->orientation == VERTICAL ? s->channel_height : s->channel_width; const float f = s->gain * w; const int ch = jobnr; float *magnitudes = s->magnitudes[ch]; @@ -1324,7 +1324,7 @@ static int calc_channel_magnitudes(AVFilterContext *ctx, void *arg, int jobnr, i static int calc_channel_phases(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) { ShowSpectrumContext *s = ctx->priv; - const int h = s->orientation == VERTICAL ? s->h : s->w; + const int h = s->orientation == VERTICAL ? s->channel_height : s->channel_width; const int ch = jobnr; float *phases = s->phases[ch]; int y; @@ -1359,7 +1359,7 @@ static void unwrap(float *x, int N, float tol, float *mi, float *ma) static int calc_channel_uphases(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) { ShowSpectrumContext *s = ctx->priv; - const int h = s->orientation == VERTICAL ? s->h : s->w; + const int h = s->orientation == VERTICAL ? s->channel_height : s->channel_width; const int ch = jobnr; float *phases = s->phases[ch]; float min, max, scale; @@ -1378,7 +1378,7 @@ static int calc_channel_uphases(AVFilterContext *ctx, void *arg, int jobnr, int static void acalc_magnitudes(ShowSpectrumContext *s) { const double w = s->win_scale * (s->scale == LOG ? s->win_scale : 1); - int ch, y, h = s->orientation == VERTICAL ? s->h : s->w; + int ch, y, h = s->orientation == VERTICAL ? s->channel_height : s->channel_width; const float f = s->gain * w; for (ch = 0; ch < s->nb_display_channels; ch++) { -- 2.52.0 _______________________________________________ ffmpeg-devel mailing list -- [email protected] To unsubscribe send an email to [email protected]