# DF-4743 VERDICT — via82c686 mixer-UAF family, 16th instance

**Status: untested** (end-to-end), **reproduced: 0**, confidence:
**certain** — same treatment as the 15 filed family instances
(DF-4156, 4193, 4299, 4334, 4344, 4421, 4457, 4468, 4504, 4537, 4550,
4552, 4610, 4651, 4724), all of which are hardware-gated.

## Static chain (line-verified)

1. `via_attach()` creates the codec (via82c686.c:544) and publishes the
   mixer at :548 — `mixer_init()` make_dev(0666 "/dev/mixerN") +
   `pdev->si_drv1 = m` with `m->devinfo = via->codec`
   (mixer.c:709,730-733; m->devinfo set in mixer_obj_create mixer.c:635).
2. Five failure paths remain after it: parent_dmat tag (:556-565),
   sgd_dmat tag (:572-582), bus_dmamem_alloc (:584-586),
   bus_dmamap_load (:587-589), pcm_register (:596). pcm_register can fail
   e.g. via the pcm veto flag; the dma paths on allocation failure.
3. `bad:` unwind calls `ac97_destroy(via->codec)` (:602 → kobj_delete +
   kfree(codec), ac97.c:852-858), `snd_mtxfree(via->lock)` (:610) and
   `kfree(via)` (:611) — **no mixer_uninit / destroy_dev anywhere**.
4. DragonFly newbus never detaches a failed attach (subr_bus.c —
   DF-4724's verified citation), so /dev/mixerN stays live, world-writable.
5. Any unprivileged user: open /dev/mixerN → mixer_open/mixer_ioctl →
   mix_getdevinfo(m) → freed codec kobj → `via_read_codec`/`via_write_codec`
   (via82c686.c:180-209) on freed `via` (wild bus_space handle, freed
   mutex) → UAF read/write in kernel context. Window: permanent (until
   reboot) once triggered.

## Live evidence gathered on the audit guest (run.log)

- `snd_via82c686.ko` ships in /boot/kernel and is wired into the build
  (sys/conf/files:2156, sys/dev/sound/driver/Makefile:5) — unlike the
  aureal sibling (DF-4724) this driver is one `kldload` away whenever a
  card is present.
- `kldload snd_via82c686` on the guest: loads cleanly; no VIA 0x30581106
  on the QEMU PCI bus → no attach, so no failure path executes.
- The load-bearing family premise (failed attach leaves a live 0666 cdev
  reachable by unprivileged open; newbus never detaches failed attaches)
  was dynamically verified on this same 6.5-DEVELOPMENT guest kernel by
  the DF-4724 run — it is newbus/mixer.c behavior, driver-independent.

## Not reproducible here

The UAF requires the physical VIA VT82C686A southbridge audio
(PCI 1106:3058) AND an attach failure after line 548. QEMU does not
emulate it; `pciconf -l` on the guest confirms absence. Hence untested,
matching every family instance's verdict.

## Bonus: DF-4116 live-reproduced during this run

While premise-testing, `kldload snd_via82c686; kldunload snd_via82c686`
panicked the guest in `sndstat_sysuninit` — a controlled A/B reproduction
(sndstat read → unload OK; reload → unload panics) of the already-filed
**DF-4116**. See `DF-4116_live_repro/` (panic.txt + NOTES.txt). Not
re-filed as a new finding; orchestrator should attach the evidence to
DF-4116 (recommend status=reproduced, impact=panic).

## Negative checks on via82c686.c (pass-2 classes considered and killed)

- **via_buildsgdt unbounded segs** (via82c686.c:232-240, writes
  `sndbuf_getsize()/ch->blksz` entries into a 4-entry/32-byte table,
  ignores sndbuf_resize result at :336): KILLED — every value reaching
  `viachan_setblocksize` comes from chn_resizebuf, whose
  `round_blksz()` floors at 16 (channel.c:1591-1609, `return ret` after
  the grow-loop) and whose maxsize clamps (channel.c:1839-1848) guarantee
  2*hblksz ≤ maxsize → sndbuf_resize(2,hblksz) always succeeds →
  segs == SEGS_PER_CHAN == 2. via8233's clamping (via8233.c:565-596,
  `ch->blksz = sndbuf_getblksz()`) is defensive, not a bug marker.
  div0 (blksz=0) also dead: chn_reset (channel.c:1190-1200) forces a
  resizebuf (→ setblocksize) at every dsp open before any trigger can run.
- **viachan_getptr garbage base** (:391-396): consumers clamp via
  `% sndbuf_getsize()` (chn_dmaupdate channel.c:377-391) — bounded.
- **setformat/setspeed**: no div0, codec_caps-gated VRA path only — fine.
- **via_intr on half-attached device** (bad: path leaves handler till
  :604 with modes pre-armed at :541-542): only fires if DMA-status INTR
  bits assert without started DMA; shared-IRQ reads of a reset codec
  clear bits — needs HW misbehavior, dropped.
- **AC97 protocol waits** (:144-176): 50×DELAY(1) polls, bounded — fine
  (contrast DF-4728's 0.35 s spins).
- **bad: unwind order**: codec destroyed while intr still armed — same
  dropped-class as above; resource release order otherwise sound
  (sgd_addr-guarded unload, NULL-guarded frees).
- **pcm_addchan returns ignored** (:597-598): worst case a registered
  device with 0 channels → open ENODEV; no memory unsafety, and no
  suspend/resume methods exist here (the DF-4539 resume-deref class
  doesn't apply).
- **via_detach**: gated on pcm_unregister success — correct.

## Recommended fix
`mixer_uninit(dev); via->codec = NULL;` on every failure after
mixer_init() (fix.diff), family idiom from DF-4724.

## 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.
