⬢ DragonFlyBSD Kernel Audit
DF-4848 / verdict.json
← back to finding ↓ download raw
{
  "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"
}