# DF-4602 — guest-wide starvation/livelock during unprivileged dsp format-change storms (INCONCLUSIVE)

**File under audit:** `sys/dev/sound/pcm/feeder_chain.c`
**Observed event class:** local DoS (kernel console spam + pcm lock churn starved a 6-vCPU guest for minutes)
**Verdict:** inconclusive — observed ONCE, NOT reproduced in 2 controlled re-runs; root-cause stack unobtainable on this rig; QEMU-without-audio-backend is a plausible confounder.

## The event (original session, 2026-09-22 ~02:00-02:12, guest booted via vm_snd.sh)

Sequence: stage 1 = 3 unprivileged fuzzers on `/dev/dsp0`,`/dev/dsp1` (30 s, no
wedge); stage 2 = 5 unprivileged fuzzers (incl. vchan clones `/dev/dsp0.N`
after `dev.pcm.0.play.vchans=4`) + concurrent **root** churn of
`dev.pcm.0.play.vchanrate` / `vchanformat` / `bitperfect` (no wedge during);
stage 3 = 3 O_RDWR fuzzers incl. the vchan node `/dev/dsp0.0` (no immediate
wedge). One to three minutes AFTER all activity, the guest entered a
minutes-long starvation state:

* sshd unusable ("Connection timed out during banner exchange") for minutes at
  a time, intermittently recovering;
* qemu host process pegged at 94-107% (≈1+ cores) with oscillating guest load;
* serial console (`wedge-serial-full.log`) shows continuing
  `pcm0/pcm1: feeder_build_format(): can't add feeder_format`,
  `feeder_build_rate(): can't set source rate`,
  `feed_format_init(): failed ...` bursts — i.e. leftover fuzzer processes
  kept cycling failing feeder-chain rebuilds against pcm channels whose
  interrupt source is dead (QEMU audio backend absent);
* no panic, no console output beyond the spam (no watchdog, no deadlock
  detector fired);
* the guest eventually self-recovered partially, then degraded again;
  a Ctrl-Alt-Esc DDB break from the QEMU monitor (`Debugger("manual escape to
  debugger")` in the serial log) stopped all CPUs, but DDB reads input from
  the serial console which is file-backed on this rig — no `ps`/`bta` was
  obtainable — so the spinner's kernel stack was never captured.

## Re-runs (controlled, after `vm.sh reset with-src`, fresh boot, vm_snd.sh)

* **rerun1 (minimal):** single unprivileged fuzzer, `/dev/dsp1`, 45 s —
  NO wedge; cpu 10-20%, ssh ok at every 10 s poll (`rerun1.log`).
* **rerun2 (full original recipe):** 5 fuzzers + identical root churn —
  cpu 96-111% for ~2.5 min as expected, ssh ok except ONE transient
  banner-exchange timeout at t+155 s, then healthy for the remaining ~4 min;
  load 0.00 at the end; fuzzers exited cleanly (`rerun2.log`).

## Why filed at all

The one-shot event was severe (whole-guest starvation from unprivileged dsp
activity + root parent-format churn) and the in-file surface is real:
`feeder_chain.c` emits **unconditional** `device_printf()` diagnostics on
every failed rebuild (`feeder_build_format` :153/:163, `feeder_build_rate`
:226/:236, `feeder_build_matrix` :304/:314, `feeder_build_volume` :359/:370,
`feeder_build_eq` :427/:437, `feeder_build_root` :470/:477,
`feeder_build_mixer` :508/:518, plus `feeder_chain` :615/:626/:638/:645/:660/
:670), and every `SNDCTL_DSP_SETFMT/SPEED/CHANNELS` on a failing format
destroys and rebuilds the whole chain (:575-579). An unprivileged user can
sustain an unbounded rate of kernel console prints through this path
(console-spam DoS surface, CWE-400). Whether that surface alone explains the
guest-wide starvation — or whether the driver/dead-interrupt environment was
the real driver — could not be established.

## Reproduce

```
# host$ dfbsd-qemu/vm.sh down && dfbsd-qemu/vm_snd.sh
# host$ dfbsd-qemu/vm.sh run_root 'kldload snd_es137x; kldload snd_hda'
build.sh   # guest, as maxx: cc -O2 -o /tmp/feeder_fuzz /tmp/feeder_fuzz.c
run.sh     # guest, as maxx: the stage-2 recipe (see file)
# watch: host qemu CPU%, ssh health, boot-snd.log spam
```

## Recommended hardening

`fix.diff` — gate the high-frequency per-ioctl failure diagnostics behind
`snd_verbose > 0` (keeps first-occurrence visibility via the existing
`bootverbose`/`snd_verbose` conventions). Clearly labeled hardening: it
removes the unbounded console-spam surface but is NOT claimed to fix the
one-shot livelock (root cause undetermined).
