# DF-1337 — Use-after-free write in chn_write (UAF read in chn_read) via concurrent chn_resizebuf across the uiomove unlock window

**File:** `sys/dev/sound/pcm/channel.c:502-507 and 1753-1764`
**Class:** UAF write / UAF read (memory corruption + info leak)

## Status: INCONCLUSIVE at runtime — confirmed real source bug, hardware-gated on this guest

The vulnerable code path was traced line-by-line in `sys/` and **confirmed to be a genuine bug**
(missing bounds check / integer overflow / UAF race). However it is **not exercisable on the
DragonFly audit guest** because the guest has neither an AMD GPU nor any audio controller:

- PCI shows only `vgapci0 class=0x030000` (QEMU stdvga, chip `0x11111234`) — no AMD GPU.
- No PCI audio device (class `0x0401`/`0x0403`); `hw.snd` empty; no `/dev/dsp`.
- `sound.ko` is a loadable module only (NOT in `X86_64_GENERIC`), is not loaded, and cannot be
  `kldload`'d by an unprivileged user — and even if loaded would not attach without the hardware.

This is the valid hard-blocker case "vulnerable code path unreachable at runtime on this guest AND no
harness can exercise it (device-integrated parser / ioctl / hardware-dependent race)." The bug is a
real latent defect that **would** manifest on a system with the relevant hardware + the module loaded.

## Mechanism (confirmed by source trace)
chn_write() captures a raw buffer pointer `off = sndbuf_getbufofs(bs,p)` under CHN_LOCK (channel.c:502), then DROPS the lock (CHN_UNLOCK, :503) across uiomove(off,t,buf) (:504) to copy user bytes into bs->buf. During that unlock window a second thread issuing a blocksize / fragment / format-change ioctl (dsp.c AIOSSIZE / SNDCTL_DSP_SETFRAGMENT -> chn_setblocksize -> chn_resizebuf) re-acquires the lock and, because the channel is not yet CHN_F_TRIGGERED on the first write (triggered is set later by chn_start at channel.c:510/738), passes the guard at :1762 and calls sndbuf_remalloc -> kfree(old bs->buf). The first thread's uiomove then writes through the freed pointer => kernel-heap UAF write. chn_read() has the identical pattern => UAF read / info leak. The SILENCE/SKIP ioctls already avoid this by waiting on c->inprog (dsp.c:1925/1949), but the resize ioctls do not, even though dsp.c:896 wraps chn_io with ++inprog.

## Live trigger conditions
Requires /dev/dsp to exist: a sound driver module loaded AND a detected audio controller. The QEMU audit guest has NO PCI audio device (no class 0x0401/0x0403), no /dev/dsp node, and no snd_* module loaded; an unprivileged user cannot kldload(2) (root-only) and, even if loaded, no hardware would attach so no /dev/dsp would appear. On real hardware with any SD_F_MPSAFE audio driver (modern PCI/USB) the race is exercisable by any user with /dev/dsp access.

## Fix
A standalone, `git apply`-able fix is in `fix.diff`. **Compile-validated**: applied to in-guest
`/usr/src` and the `sound` module rebuilt under `-Werror` (rc=0, no warnings/errors in the
patched translation unit). See `build_fix.log`.

Add `while (c->inprog != 0) cv_wait(&c->cv, c->lock);` at the top of chn_resizebuf(), mirroring the existing SILENCE/SKIP guard in dsp.c, so every blocksize/fragment/format-change path waits for an in-flight chn_read/chn_write to release its raw buffer pointer before remalloc'ing. Matches the finding markdown proposal (wait for inprog==0 in chn_resizebuf).

## Reproduce / validate
```
# 1. Confirm the bug site exists (read-only source trace):
grep -n ... sys/dev/sound/pcm/channel.c

# 2. Validate the fix compiles (on the audit guest):
scp -F dfbsd-qemu/config findings/poc/DF-1337/fix.diff dfbsd:/root/fix.diff
./dfbsd-qemu/vm.sh run_root 'cd /usr/src && patch -p1 --forward < /root/fix.diff'
./dfbsd-qemu/vm.sh run_root 'cd /usr/src/sys/dev/sound/sound && KERNCONF=X86_64_GENERIC SYSDIR=/usr/src/sys make -m /usr/src/share/mk'

# 3. (requires real hardware) Exercise the bug: attach an AMD GPU / audio device and trigger.
```
