DF-4848 / verdict.json
{ "finding_id": "DF-4848", "status": "reproduced", "reproduced": 1, "impact": "none", "confidence": "certain", "verdict": "Reproduced at feeder level on the audit guest against the real, unmodified sys/dev/sound/pcm/feeder_volume.c: feed_volume_feed():277 divides the SOURCE FEEDERS RETURN with the inexact generated SND_FXDIV - and that dividend is user-paced (feed_root returns min(count, sndbuf_getready), i.e. exactly what the unprivileged user write()s). For bad-residue returns inside the claimed [1,65536] domain (first bad: 32768@align6, 16384@align10, 8195@align12, 5473@align14) FXDIV returns floor+1 frames, so apply() reads AND writes a frame past the fed data (past the destination window when ret==count - harness: count=32771 align=6 ret=32772, REAR guard hit), and :284-286 count -= j*align UNDERFLOWS to ~4GiB when j>count, re-arming the loop to ask the source for a wild window at dst+overrun - with more data ready the source then writes up to bufsoft-ready bytes of user-controlled audio PAST the window end (directed heap overflow; bounded only by the users pending write data). feeder_volume is default for every vchan child (feeder_chain.c:713-716, SD_F_VPC, snd_maxautovchans=16 default) and 3/5/6/7-channel formats are unprivileged SNDCTL_DSP_CHANNELS choices. Harness: 2810/21604 checks fail baseline; 0 with the fixed generator. In-kernel churn showed no differential anomaly on this no-INVARIANTS kernel (logs in DF-4849 pack).", "exploit_chain": "unprivileged: open /dev/dsp (vchan) -> SNDCTL_DSP_CHANNELS=6 (align 12) -> pace write() sizes so the feed return lands on a bad residue (>=8195, ~29% of values) with more data pending -> volume feeder miscounts a frame, writes past the window, and on a full window underflows count -> second-pass source fill writes attacker-paced user audio bytes past the destination scratch (to->tmpbuf / format feeder tail) into adjacent kernel heap.", "evidence": "vol.log (baseline: checks=21604 failures=2810, FAIL[T1 write] ch=3 align=6 count=32771 ret=32772 REAR guard (write past window) maxoff=32772 + T2 underflow re-arm audit lines); vol_fixed.log (fixed: 0); ffvol.c/fxshim.h/fxsrc.c; VERDICT.md", "kernel_refs": [ "sys/dev/sound/pcm/feeder_volume.c:277", "sys/dev/sound/pcm/feeder_volume.c:282", "sys/dev/sound/pcm/feeder_volume.c:284-286", "sys/dev/sound/pcm/feeder.c:466", "sys/dev/sound/pcm/feeder_chain.c:713-716", "sys/dev/sound/pcm/sound.c:62", "sys/dev/sound/pcm/buffer.c:705", "sys/tools/sound/snd_fxdiv_gen.awk:56-71" ], "poc_changes": "Fresh harness (DF-4846 infrastructure) plus a complete fake struct pcm_channel (c->volume[][]) with non-flat volumes so the bypass paths do not short-circuit; desc->type must be FEEDER_VOLUME for feeder_volume_apply_matrix.", "attempts": 3, "guest_uname": "DragonFly dfbsd 6.5-DEVELOPMENT DragonFly 6.5-DEVELOPMENT #0: Thu Jul 2 06:02:54 UTC 2026 root@dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC x86_64", "runtime_sec": 600, "guest_dirty": 0, "build_cmd": "cd /root/fx && sh build.sh; cc -O1 -g -o ffvol ffvol.c fxsrc.c", "run_cmd": "./ffvol # baseline FAIL; cp snd_fxdiv_gen_fixed.h snd_fxdiv_gen.h; rebuild -> ALL PASS", "code_hash": "", "notes": "Distinct from DF-4710/DF-4846/4847: the misrounded dividend is the user-paced SOURCE RETURN, not the entry count - gives the strongest control (attacker chooses the exact dividend via write() pacing) and the count-underflow re-arm gives a length-directed write primitive. Shared table root cause; one generator fix clears all four harnesses.", "recommended_fix": "Fix snd_fxdiv_gen.awk (domain-exact reciprocals + 64-bit multiply, fix.diff); defensively, clamp j*align <= count in feed_volume_feed before the loop decrement.", "fix_status": "fixed", "fix_baseline_reproduced": 1, "fix_patched_reproduced": 0, "fix_verdict": "A/B at harness level, only the generated header swapped: 2810 failures vs 0 (vol.log vs vol_fixed.log). Kernel rebuild A/B not performed (null in-kernel baseline observable on this no-INVARIANTS rig, same standard as DF-4710).", "fix_evidence": "vol_fixed.log (failures=0); fix.diff; snd_fxdiv_gen_fixed.awk" } |