# VERDICT — DF-4334 (via8233.c attach-path mixer UAF)

**Status: untested (attach-failure-gated, source-certain). Severity Low. Confidence certain.**

## The bug (source chain, every step cited)

1. `via_attach()` initializes hardware, then creates the codec:
   `via->codec = AC97_CREATE(dev, via, via_ac97)` — via8233.c:1331
   (ac97.c:1012-1030: `codec->devinfo = via`, kobj methods allocated).
2. `mixer_init(dev, ac97_getmixerclass(), via->codec)` — via8233.c:1335 —
   its return value is **ignored**. Inside mixer_init:
   `m = mixer_obj_create(dev, cls, devinfo=codec, ...)` stores the codec as
   `m->devinfo` (mixer.c:635 area) and `make_dev(&mixer_ops, ..., 0666,
   "mixer%d")` publishes the world-writable node with `pdev->si_drv1 = m`
   (mixer.c:730-733). `snddev->mixer_dev = pdev`.
3. The next failure point is `pcm_register(dev, via, ..., NWRCHANS)` —
   via8233.c:1354-1355 — which returns non-zero when
   `pcm_veto_load != 0` (sound.c:1021-1025; the variable is initialized
   to **1** at sound.c:50 and cleared only by successful feeder
   registration at boot, feeder.c:120-126) or when
   `device_get_unit(dev) > PCMMAXUNIT` (=255, sound.c:1027-1034,
   sound.h:107).
4. `goto bad` unwinds with `ac97_destroy(via->codec)` — via8233.c:1372-1373 —
   which `kobj_delete(codec->methods)`s the dispatch table, frees the codec
   lock and `kfree(codec, M_AC97)` (ac97.c:852-858). **No `mixer_uninit()`
   runs anywhere on this path** (device attach failed, so `via_detach` /
   `pcm_unregister` are never called; sound.c:1205 shows the canonical
   unwind does `mixer_uninit` first).
5. Result: the 0666 `/dev/mixerN` remains registered forever with
   `si_drv1` pointing at the freed `snd_mixer` → freed `devinfo` codec →
   freed kobj method table. Any later `open`/ioctl on that node (e.g.
   `SOUND_MIXER_READ_DEVS` → `mixer_ioctl` → `MIXER_GETDEV(m->devinfo)`)
   is a use-after-free with indirect-dispatch potential through
   `kobj_delete`d memory.

This is the same defect family the audit already verified by source in
maestro (DF-4156), es137x (DF-4193) and emu10kx-pcm (DF-4299); via8233.c
is a fourth instance that pass 1 missed. FreeBSD upstream (current head)
sidesteps the class by making `pcm_register()` void — its file has no
post-mixer_init failure path at all; DragonFly kept the check, keeping
the bug reachable.

## Why untested (not false-positive)

- The trigger needs an actual VIA 1106:3059 audio function whose attach
  runs to `mixer_init` and then fails at `pcm_register`. The audit guest
  has **no 1106:3059 function**: host QEMU is 7.2.22
  (`-device help` lists only AC97/ES1370/intel-hda) and the via-ac97
  emulation (hw/audio/via-ac97.c, rev 0x50 → probe-match "VIA VT8235",
  config 0x40=1 codec-ready) only exists from QEMU 8.2.
- Even with the hardware, both `pcm_register()` failure preconditions are
  boot-time anomalies (`pcm_veto_load` feeder-init failure / >255 pcm
  units) that an unprivileged user cannot create — same verdict logic as
  DF-4156. Hence Low severity, `impact: none` demonstrated,
  `confidence: certain` in the source chain.

## PoC artifacts

- `via8233_probe.c` + `build.log`/`run.log`: guest-side proof of the
  negative environment (no mixer node, no 1106:3059, module absent).
- `env.txt`: guest uname, host QEMU version/device list.

## Fix

`fix.diff` (git-apply-able against the read-only sys/ tree; never applied
there): move `pcm_register()` before `AC97_CREATE`/`mixer_init()` and
fail attach on `mixer_init()` error. After the reorder, no failure path
exists after the mixer is published, so the `bad:` unwind stays
symmetric — no `mixer_uninit` bookkeeping needed. Not validated on the
guest for the same hardware-absence reasons (fix_status: not_testable);
`git apply --check` clean against sys/dev/sound/pci/via8233.c.

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