# DF-4095 — emu_intr2 calls sc->mpu_intr/sc->mpu locklessly, racing detach teardown (UAF)

File: `sys/dev/sound/pci/emu10k1.c` (pass 2, GLM 5.3) — DF-3867 family shape
(the emu10kx sibling finding was a NULL-function-pointer call during
unregister; here the analogous race is on the mpu401 callback plumbing).

## What

    static void                     /* emu10k1.c:1196-1203 */
    emu_intr2(void *p)
    {
            struct sc_info *sc = (struct sc_info *)p;

            if (sc->mpu_intr)
                (sc->mpu_intr)(sc->mpu);
    }

- `sc->mpu_intr` is set by `mpu401_init(..., &sc->mpu_intr)` in
  `emu_midiattach()` (emu10k1.c:1214) — mpu401 writes `mpu401_intr` into it
  (mpu401.c:188).
- It is cleared under `sc->lock` by `emu_muninit()` (emu10k1.c:1175-1185),
  which runs during `mpu401_uninit()` ← `emu_uninit()` ← `emu_pci_detach()`
  (emu10k1.c:2038-2039, 2172).
- `mpu401_uninit()` then kfrees the `struct mpu401` that `sc->mpu` points
  at (mpu401.c:197-204).

`emu_intr2` takes **no lock**. It is registered as the mpu401 soft-interrupt
callback (`m->si = softintr`, mpu401.c:181) and is invoked asynchronously
from the `mpu401_timeout` callout (mpu401.c:108-109), which is rearmed by
`mpu401_intr()` whenever MIDI TX is enabled (mpu401.c:162-164, 241).

Race at detach with MIDI TX active:

    callout(emu_intr2)                     emu_pci_detach
    ----------------                       ----------------
    if (sc->mpu_intr)   != NULL
                                           emu_uninit -> mpu401_uninit
                                           -> midi_uninit -> emu_muninit:
                                              lock; sc->mpu_intr = 0; unlock
                                           kfree(m)          /* mpu401.c:203 */
    (sc->mpu_intr)(sc->mpu)
      -> mpu401_intr(freed m)  /* UAF read/write of struct mpu401 */

The check-then-call on `sc->mpu_intr` is unsynchronized with the
clear-and-free on the other CPU. Result: `mpu401_intr()` executes against a
freed `struct mpu401` (reads/writes its registers via STATUS()/READ()/
WRITE() macros that dereference `m`), i.e. a heap UAF. Note the hardware-IRQ
path is safe — `emu_intr()` calls the same pointer *while holding sc->lock*
(emu10k1.c:1225, 1258-1263), serialized against `emu_muninit`. Only the
callout path through `emu_intr2` is lockless.

(Companion hazard inside mpu401.c itself — `mpu401_timeout` reading `m->si`
from possibly-freed `m` — is an mpu401.c defect and noted here only for
context; this finding is the emu10k1.c lockless call site.)

## Threat model

Requires an emu10k1-family card, an active MIDI TX stream, and device
detach (or unload path that reaches emu_uninit) racing the 1-tick callout.
Hardware-gated; narrow window; consequence is kernel UAF (panic; potential
corruption given heap reuse). Severity Low (reachability), memory-safety
class (UAF).

## Fix

Serialize the check+call under the same mutex the teardown uses (see
fix.diff). This mirrors the already-locked call in `emu_intr()`
(emu10k1.c:1258-1263) — `mpu401_intr` already executes under `sc->lock`
there, so no new lock-order is introduced.

## Reproduce

Hardware-gated (QEMU does not emulate emu10k1 — probe evidence in run.log).
Source-level certainty of the missing lock; race exploitability is
rated `likely` (window exists, but never triggered on this guest).
