# DF-4753 — cxm(4) msp34xxx audio-decoder calls run unserialized against cxm_detach → UAF

**File:** `sys/dev/video/cxm/cxm_msp34xxx.c` (pass 2; root cause shared with cxm.c)

## What

Every exported `cxm_msp_*` function dereferences `sc` / `sc->iicbus` /
`sc->dev` with **no lock anywhere in the driver** (`struct cxm_softc`
(cxm.h:216-264) has no lock member; there is no `priv_check` in cxm.c):

* `cxm_msp_init` `cxm_msp_dpl_reset(sc->iicbus, ...)` (cxm_msp34xxx.c:295),
* all of `cxm_msp_dpl_read/write` dispatch through `sc->iicbus`
  (cxm_msp34xxx.c:230/266 via callers at :298,:302,:338,:365,...),
* `cxm_msp_wait_for_lock` tsleeps 10 × hz/20 (**~500 ms window**)
  (cxm_msp34xxx.c:601-622) and then logs through `sc->dev`
  (cxm_msp34xxx.c:624).

The ioctl surface reaching these is **unprivileged**: `/dev/cxmN` is created
mode **0444** (cxm.c:1885-1886) so any user can `open(O_RDONLY)`, and DF devfs
does not gate `ioctl()` on the open mode:

```
unprivileged ioctl(BT848_SAUDIO, AUDIO_TUNER)     cxm.c:2358
  -> cxm_pause_encoder / cxm_msp_select_source    cxm.c:2401-2404
  -> cxm_encoder_wait_for_lock                    cxm.c:~1510
  -> cxm_msp_autodetect_standard                  cxm.c:1574
  -> cxm_msp_wait_for_lock (sleeps ~0.5 s)        cxm_msp34xxx.c:588-626
```

While such an ioctl sleeps, privileged `kldunload cxm` (module ships as
`/boot/kernel/cxm.ko`) runs `cxm_detach` (cxm.c:1944-2004), which
`dev_ops_remove_minor()`s the cdev, detaches the I2C bus children
(cxm.c:1993-1996) and, at module unload completion, the devclass frees the
softc. The sleeping ioctl then wakes into freed memory: reads `sc->iicbus`
(garbage/NULL → method dispatch on a dangling `device_t`), and
`device_printf(sc->dev, ...)` (cxm_msp34xxx.c:624) dereferences a dangling
`sc->dev`. Secondary defect in the same no-locking family: `cxm_open`'s
`is_opened` check-then-set is unlocked (cxm.c:2158-2161), so racing opens
defeat the single-open serialization and interleave I2C transactions.

This is the cxm twin of bktr's DF-4419; the cxm.c pass-1/pass-2 audits
(DF-1295, DF-3941) never covered the detach-vs-ioctl lifetime hole.

## Impact

Low — triggering the *freeing* side requires privilege (kldunload / PCI
hot-remove), exactly like DF-4419 (bktr, Low). Once triggered: reliable
use-after-free deref (NULL/garbage `device_t` vtable dispatch, dangling
`sc->dev`) → kernel panic; heap-reclaim exploitation is theoretically
possible but not developed (hardware-gated).

## Reproduce (hardware-gated)

`cxm_uaf_race.c` + `run.sh`: victim child hammers `BT848_SAUDIO`; root parent
loops `kldunload cxm; kldload cxm`. **Requires a Conexant iTVC15/16 card.**
On the audit guest: `kldload cxm` succeeds but no `/dev/cxm*` appears (no
card) → trigger exits 3.

## Fix

`fix.diff` (cxm.h + cxm.c): add `struct lock cxm_lock`, serialize
open/close/ioctl, and drain it in `cxm_detach` before tearing the softc
apart. Compile-validated as the full cxm.ko module with `-Werror`
(fix_build.log).
