Source: libsndfile Version: 1.2.2-4 Severity: important Tags: security upstream patch X-Debbugs-Cc: [email protected]
Hi, The W64 and RF64 readers accept repeated 'fmt ' chunks. A later chunk can raise sf.channels while psf->channel_map still has the size allocated for the first chunk (wavlike_read_fmt_chunk only reallocates it in the WAVE_FORMAT_EXTENSIBLE branch). SFC_GET_CHANNEL_MAP_INFO then checks the caller's datasize against the new channel count and copies that many entries out of the old, smaller buffer. wav.c already ignores a second 'fmt ' chunk; rf64.c and w64.c do not. This is upstream issue 968, which is still open and reports the crash through sndfile-convert (copy_metadata) on an RF64 file. I found no CVE for it, and nothing about it in the tracker or the open libsndfile bugs. Upstream fix: commit 59f33be, "rf64, w64: ignore a second 'fmt ' chunk" (from pull request 1149). It is on master; there has been no release since 1.2.2. Tested on 1.2.2-4 ----------------- I built the 1.2.2-4 source with all Debian patches applied, using clang with ASan and UBSan, and opened the W64 test input that upstream's commit adds to tests/command_test.c (first 'fmt ' has 1 channel and is extensible, second claims 64 channels). A small program then called SFC_GET_CHANNEL_MAP_INFO with a buffer sized for sf.channels: AddressSanitizer: heap-buffer-overflow, READ of size 256 in sf_command 0 bytes after the 4-byte region allocated in wavlike_read_fmt_chunk (wavlike.c:351) The bytes read end up in the caller's buffer as channel map entries, so this is an information leak as well as a possible crash. The size of the over-read follows the channel count in the file. With the source hunks of 59f33be applied, the same input opens as 1 channel with no sanitizer report. The project's test suite passes 143 of 143 both with and without the patch. I only saw the ASan report through the W64 path. Upstream's RF64 test input does not create a channel map, so it produced no report, but it did open as 64 channels without the patch and 1 channel with it, and the missing check in rf64.c is the same. Other suites ------------ The attached patch (the rf64.c and w64.c hunks of 59f33be with DEP-3 headers) passes patch --dry-run against 1.2.2-4 and against the patched sources of 1.2.2-2+deb13u1 (trixie) and 1.2.0-1+deb12u1 (bookworm). I did not build or test those two. Regards, Sumit Verma
Description: rf64, w64: ignore a second 'fmt ' chunk A second 'fmt ' chunk can raise sf.channels after the channel map (allocated for the first chunk's channel count) has been set up, so SFC_GET_CHANNEL_MAP_INFO copies past the end of that heap buffer. wav.c already ignores repeated 'fmt ' chunks. Source hunks of the upstream commit, without its test changes. Origin: upstream, https://github.com/libsndfile/libsndfile/commit/59f33be Bug: https://github.com/libsndfile/libsndfile/issues/968 Last-Update: 2026-11-08 --- diff --git a/src/rf64.c b/src/rf64.c index 3b890e6..9bedddd 100644 --- a/src/rf64.c +++ b/src/rf64.c @@ -257,6 +257,12 @@ rf64_read_header (SF_PRIVATE *psf, int *blockalign, int *framesperblock) break ; case fmt_MARKER: + if (parsestage & HAVE_fmt) + { psf_log_printf (psf, "*** Second 'fmt ' chunk?\n") ; + psf_binheader_readf (psf, "j", chunk_size) ; + break ; + } ; + psf_log_printf (psf, "%M : %u\n", marker, chunk_size) ; if ((error = wavlike_read_fmt_chunk (psf, chunk_size)) != 0) return error ; diff --git a/src/w64.c b/src/w64.c index fa5ade3..8ff3914 100644 --- a/src/w64.c +++ b/src/w64.c @@ -277,6 +277,11 @@ w64_read_header (SF_PRIVATE *psf, int *blockalign, int *framesperblock) if ((parsestage & (HAVE_riff | HAVE_wave)) != (HAVE_riff | HAVE_wave)) return SFE_WAV_NO_FMT ; + if (parsestage & HAVE_fmt) + { psf_log_printf (psf, "*** Second 'fmt ' chunk?\n") ; + break ; + } ; + psf_log_printf (psf, " fmt : %D\n", chunk_size) ; /* size of 16 byte marker and 8 byte chunk_size value. */

