# DF-4344 VERDICT

**Status: inconclusive (kernel runtime hardware-gated — no ATI IXP audio
controller exists on the audit guest; defect certain at source level, the
5th verified instance of the DF-4156 family).**

## Root cause (code-proven)

`atiixp_chip_post_init` (atiixp.c:1001-1115):

```
1085:  mixer_init(sc->dev, ac97_getmixerclass(), sc->codec);   <-- publishes 0666 /dev/mixerN
1087:  if (pcm_register(sc->dev, sc, ATI_IXP_NPCHAN, ATI_IXP_NRCHAN))
1088:          goto postinitbad;                                <-- still-failing step
...
1113: postinitbad:
1114:  atiixp_release_resource(sc);                             <-- frees codec + sc
```

`mixer_init` (mixer.c:687-737) does `make_dev(&mixer_ops, ..., 0666,
"mixer%d", unit)` and stores the mixer (whose devinfo is the codec) in
`pdev->si_drv1`. Nothing in the failure path removes that cdev.
`atiixp_release_resource` then does `ac97_destroy(sc->codec)`
(atiixp.c:1129-1132; `kobj_delete(codec->methods)` + `kfree(codec)`,
ac97.c:852-859) and `kfree(sc, M_DEVBUF)` (atiixp.c:1165).

Result: any later `open`/`ioctl` on `/dev/mixerN` reaches
`mixer_ioctl` → `mix_getdevinfo(m)` → freed codec, with dispatch through
the deleted kobj methods table (indirect-call UAF), plus `snddev->…`
state pointing at freed `sc`.

Secondary consequences of the same root:
- The device stays attached (attach returned 0 at atiixp.c:1302 long
  before the delayed hook runs, and even the synchronous cold==0 branch
  returns 0). `atiixp_pci_suspend` (atiixp.c:1337) does
  `atiixp_lock(sc)` on the devinfo `pcm_register` never stored →
  `pcm_getdevinfo` NULL → `snd_mtxlock(NULL)` → NULL-deref panic.
- `atiixp_pci_detach` (atiixp.c:1315-1321) only unregisters when
  `sc->codec != NULL`; on this path it reads the stale softc pointer and
  either skips cleanup (mixer cdev + devnode leak, permanent UAF) or
  touches freed memory.

`pcm_register` failure modes on this path (sound.c:1016-1035):
`pcm_veto_load` (EINVAL — feeder init failure at boot) or
`device_get_unit(dev) > PCMMAXUNIT` (ENODEV). Both are operator/config
controlled, not attacker-on-demand — hence Low severity, matching the
family (DF-4156/4193/4299/4334 all Low).

## Reproduction attempt on the audit guest

Guest: DragonFly 6.5-DEVELOPMENT X86_64_GENERIC (env below), QEMU 7.2
class emulator. `pciconf -l`: no vendor 0x1002 device of any kind — the
ATI IXP 200/300/400/SB600 AC97 controllers (1002:4341/4361/4370/4382)
are not emulated. Probe evidence (`guest_check.log`):

- `kldload snd_atiixp` succeeds (registers the driver),
- `devinfo` shows **NO_PCM_DEVICE_ATTACHED** — `atiixp_pci_probe`
  returns ENXIO for every PCI device, `atiixp_pci_attach` never runs,
  so the buggy `postinitbad` path is unreachable on this guest.

Therefore: kernel-runtime reproduction impossible here (hardware-gated),
same classification the family got; the code defect itself is certain —
byte-for-byte the same failure-ordering construct already verified in
four sibling drivers.

Incidental capture (`panic_df4116_on_atiixp_unload.txt`): attempting to
unload the module to at least exercise teardown panics in
`sndstat_sysuninit` — that is **known DF-4116** (already filed against
sys/dev/sound/pcm/sndstat.c), not re-reported here.

## Fix validation

`fix.diff` (git apply --check OK against the pristine tree):
tear the mixer down before releasing everything it points at:

```c
postinitbad:
	if (mixer_created && mixer_uninit(sc->dev) == 0)
		sc->codec = NULL;	/* mixer_uninit ac97_destroy'd it */
	atiixp_release_resource(sc);
```

`mixer_uninit` (mixer.c:767-822) does `destroy_dev(pdev)` and
`MIXER_UNINIT(m)` → `ac97mix_uninit` → `ac97_destroy(codec)`
(ac97.c:1030-1038) — i.e. it removes the dangling cdev AND the codec
exactly once; NULLing `sc->codec` keeps `atiixp_release_resource`'s
`ac97_destroy` (atiixp.c:1129) from double-freeing. A kernel-build
validation was not possible: building and booting an atiixp-attachable
kernel requires the physical controller (probe gates attach), which the
guest cannot emulate. fix_status: inconclusive (not
hardware-demonstrable here), logic reviewed against the mixer.c/ac97.c
teardown paths.

## Negative results (pass-2 depth on atiixp.c, classes hunted & killed)

- **DMA descriptor ring geometry** (atiixp.c:1272-1287, 474-478,
  579-603): allocation is `CHSEGS_MAX(256) * NCHANS(2) * 12` ops;
  `atiixp_chan_init` slices per channel at `num*256` with
  `registered_channels` only ever reaching NCHANS=2 (pcm_addchan called
  exactly NPCHAN+NRCHAN=2 times, atiixp.c:1090-1093; vchans use their own
  class). `buildsgdt` writes `< blkcnt ≤ 256` entries per slice — in
  bounds. `next` pointers stay inside the slice. u16 `size` field:
  blksz>>2 ≤ 16384 fits (polling mode single-descriptor case included).
  CLEAN.
- **Fragment/buffer math** (atiixp.c:529-566): blksz aligned/ clamped to
  [32, maxsize/2], blkcnt to [2,256]; halving loop guarantees
  blksz*blkcnt ≤ maxsize before `sndbuf_resize`, and `sndbuf_resize`
  (buffer.c:161-205) independently rejects blksz*blkcnt>maxsize /
  blkcnt<2 / blksz<16 — no div0, no oversize descriptors.
  `sc->blkcnt` hint path (atiixp.c:1236-1252): a `blocksize` hint larger
  than bufsz makes blkcnt=0 → `1 << (i-1)` with i=0 is UB, but on x86 it
  yields 0x80000000 which the subsequent unsigned clamp maps to
  CHSEGS_MAX; root-only tunable; no memory-safety impact. KILLED.
- **pollticks division** (atiixp.c:741-743, 783-785): divisor is
  align*spd; speed is pinned to 48000 by `atiixp_chan_setspeed`
  (atiixp.c:522-527) and align ∈ {1,2,4,8} post-format — the pcm core
  negotiates format/speed before any trigger. Not reachable with 0.
  KILLED.
- **Codec ready waits** (atiixp.c:360-405): all bounded (500 × DELAY(1)
  in waitready, 500 in rdcd's data phase) — bounded, under lock, fine.
  CLEAN.
- **SPDIF paths**: no spdif channel/parse code exists in this driver;
  only register-bit mentions (atiixp.c:235-236, 813-814, 947). N/A.
- **Suspend/resume** (atiixp.c:1330-1404): `atiixp_pci_suspend`
  computes `value |= POWERDOWN|AC_RESET` but writes only
  `ATI_REG_CMD_POWERDOWN` (atiixp.c:1354-1355) — cosmetic logic wart
  (AC_RESET never written), no security impact. The NULL-scuttled
  suspend entry is part of THIS finding's root. `mixer_reinit` failure
  returns ENXIO leaving interrupts disabled — availability-only, same
  attach-failure precondition. NOTED, not filed.
- **detach leak symmetry** (atiixp.c:1310-1328): consistent with family;
  `pcm_unregister` (sound.c:1205) performs mixer_uninit internally, so
  the normal detach path does not double-free. CLEAN.

## Bottom line

Certain, Low (attach-failure-gated, not user-triggerable on demand),
5th instance of the DF-4156 family in sys/dev/sound/pci/. Runtime proof
requires IXP hardware the guest cannot emulate; defect and fix are
code-certain by symmetry with the four verified siblings.

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