feed_eq_init accepts AFMT_CHANNEL counts beyond the [SND_CHN_MAX] biquad state arrays (missing bound check; sample-driven function-pointer corruption if the invariant ever breaks)
Summary
init copies AFMT_CHANNEL into info->channels with no validation while the per-channel state arrays are [SND_CHN_MAX=8] - the sibling feeder_volume validates exactly this, as does this file's own setter. Demonstrated on the pristine file at -O0: 9 channels silently corrupts treble.gain with a sample-derived value used as the next coeff index (wild OOB read); 11+ channels corrupts the biquad function pointer and CALLS it (SIGSEGV); gcc -O2 independently warns. Not kernel-reachable today (all callers clamp); defense-in-depth. Mirror-the-sibling-check fix (validated).
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-4711 Β· 17 files| File | Type | Description | Size | |
|---|---|---|---|---|
| dbg4.c | β | 1.9 KB | view raw | |
| eqshim.h | β | 5.9 KB | view raw | |
| feeder_eq.c | β | 17.4 KB | view raw | |
| feeder_eq_gen.h | β | 21.8 KB | view raw | |
| snd_fxdiv_gen.h | β | 3.6 KB | view raw | |
| build.sh | β | 65 B | view raw | |
| run.sh | β | 89 B | view raw | |
| build.log | β | 1.1 KB | view raw | |
| run.log | β | 130 B | view raw | |
| oob_8.log | β | 112 B | view raw | |
| oob_9.log | β | 130 B | view raw | |
| oob_11.log | β | 0 B | β download | |
| oob_16.log | β | 0 B | β download | |
| divergence.log | β | 68 B | view raw | |
| env.txt | β | 332 B | view raw | |
| fix_4711.diff | β | 425 B | view raw | |
| code_hashes.txt | β | 467 B | view raw |
Fix verification
fixedA/B validated at feeder level: patched copy rejects ch=9/16 with EINVAL (init error path; harness NULL-deref crash in the oob branch is the harness's, not the file's) while ch=8 remains fully functional - 32.4M-check soak 0 failures (DF-4710 pack, run.2.log).
fix_4711.diff; DF-4710/run.2.log (patched full soak)
Confirmed kernel references
Detail
Evidence (decisive lines)
run.log (=oob_9.log: init=0 channels=9 ... treble.gain=194117774 (was 0) bass.gain=-1968349141); oob_11.log/oob_16.log (SIGSEGV via called clobbered info->biquad); oob_8.log (clean invariant); divergence.log (-O2 build divergence); build.log (gcc UB warning)
PoC changes
Authored fresh in pass 2 (no seed): dbg4.c drives feed_eq_init/feed_eq_feed of the pristine file with a >8-channel SND_FORMAT and a PRNG sample source; eqshim.h provides the faithful userland shims.
Verified recommended fix
Add the feeder_volume.c:148 channel guard to feed_eq_init (fix_4711.diff).
Verdict
Reproduced (consequence) on the real, unmodified feeder_eq.c at -O0 on the guest: a 9-channel format flows unchecked through feed_eq_init (feeder_eq.c:362 has no SND_CHN_MAX guard, unlike feeder_volume.c:148) into info->channels while the biquad state arrays are [SND_CHN_MAX=8] - after ONE feed, treble.gain is corrupted 0 -> 194117774 by audio-sample-derived OOB writes (next feed uses it as info->coeff[gain]: wild OOB read); at 11+ channels the OOB writes reach the info->biquad function pointer and it is CALLED (SIGSEGV); gcc 8.3 -O2 independently flags 'iteration 8 invokes undefined behavior' and builds observably diverge. NOT kernel-reachable today: every descriptor producer clamps channels to SND_CHN_MAX upstream (dsp.c:1499-1500, mixer.c:260-261, snd_str2afmt max 7.1) - hence Info severity: defense-in-depth gap only.
No comments yet.