# DF-4849 — VERDICT

**status: reproduced** (feeder level, real unmodified code on the audit guest)
**primitive:** (M1) persistent sndbuf ring overflow — mixer returns more
bytes than the destination has free; (M2) `mcnt` unsigned underflow arming a
~4GiB `memset` at `b + rcnt` — caught verbatim by the harness:
`MEMSET-BOMB: memset(b + 65556, 0x00, 4294967284)`
**confidence: certain** (M1 direct on pristine code; M2 mixer logic proven on
pristine code with the child-overshoot precondition demonstrated separately
on real feeder_format/feeder_volume code — DF-4846/DF-4848)

## Root cause

`feed_mixer_feed` (feeder_mixer.c:279-388):

1. `:299` `count = SND_FXROUND(count, sz)` — the caller (sndbuf_feed,
   buffer.c:708) passes `count = min(free, maxfeed)`; for bad-residue free
   values (first bad 8195 for sz 12; 15–40% of values ≥ first_bad) the
   generated table misrounds UP (shared snd_fxdiv_gen.awk defect — see
   DF-4846), so count > free. Children are asked for `count` and fill it into
   `b`; the mixer returns rcnt = count > free. Kernel side:
   `sndbuf_acquire(to, tmpbuf, rcnt)` with rcnt > free copies past the free
   region (ring overwrite of live audio) and inflates `b->rl` past
   `b->bufsize` — `sndbuf_getfree = bufsize - rl` then wraps unsigned
   (buffer.c:615-636; only KASSERT-protected in production).

2. `:339-364` `rcnt = SND_FXROUND(FEEDER_FEED(ch->feeder, ...), sz)` — the
   FXROUND of a child's return. If the child returns more than asked
   (`count + delta` — exactly what DF-4846 proves feeder_format does and
   DF-4848 proves feeder_volume does on the same misrounds), rcnt can exceed
   count, and `:362` `mcnt = count - rcnt` underflows (e.g. 65544 − 65556 →
   0xFFFFFFF4 = 4294967284). `:368` then executes
   `memset(b + rcnt, sndbuf_zerodata(...), mcnt)` — a ~4GiB kernel heap
   memset 12 bytes past the window base — total memory destruction
   (panic at best).

## Reproduction (guest, pristine file)

`ffmix` (`mix.log`):
```
FAIL[M1 ring overflow] count_in(free)=8195 FXROUND=8196 rcnt=8196  (+1 bytes past free)   [500/500]
M2: child0 (feeder_format-style) returns count+8; FXROUND(65544+8, 12) = 65556 > count 65544
MEMSET-BOMB: memset(b + 65556, 0x00, 4294967284) [mixer count window was 65544 => mcnt underflow]
```
exit code 42. The M2 child stub returns count+8 — a delta class the
fxfmt/ffvol harnesses produce from REAL feeder code (e.g. feeder_format
count=65548 → 65556).

## Kernel reachability

- Vchan mixing is default: `snd_maxautovchans = 16` (sound.c:62); every pair
  of `/dev/dsp` opens becomes children of one parent mixed by feed_mixer_feed
  (feeder_mixer.c:314-380). The parent format follows the first child
  (vchan sync), giving non-pow2 sz (12/14) via unprivileged channel ioctls.
- M1 needs only: free landing on a bad residue ≥ 8195 (user-paced drain) —
  a large fraction of feeds on 8K–64K buffers.
- M2 needs the additional conjunction of an overshooting child head feeder
  (DF-4846/DF-4848-proven) and ≥ 2 busy children — all unprivileged,
  default-config choices.

## In-kernel attempt (honest)

ES1370 + 6ch/7ch vchan children + bad-residue pacing (`churn_bad.log`,
`churn_dmesg.txt`): the "channel dead" events occur equally in the ALIGNED
CONTROL run (`ctlchurn.c`) — an ES1370-without-audiodev emulation artifact,
not differential, so no in-kernel anomaly is attributable to the defect on
this no-INVARIANTS rig — the expected outcome for ring-level overflow
(silent) and the memset (would be instantly fatal if its composite
conjunction fired; it did not on this rig within the bounded churn).

## Fix validation

`fix.diff` (generator): baseline = M1 500/500 fails + memset bomb (exit 42);
fixed = **0 failures, no bomb** (`mix.log` vs `mix_fixed.log`).
fix_status: fixed. Recommended hardening independent of the generator:
clamp `rcnt` to count at :362 (`if (rcnt > count) rcnt = count;`) so no
feeder-contract violation anywhere in the tree can ever arm the giant memset.

## Fix status (batch validation)
Applied with the 36 sibling fix.diffs of this batch in findings/poc/_batch41/all_fixes.patch; single in-guest `make -j6 nativekernel KERNCONF=X86_64_GENERIC` completed RC=0 with zero errors under -Werror (full log: findings/poc/_batch41/fix_build8.log). Behavior A/B intentionally skipped for this Info-tier item.
