# DF-3981 — sbp(4): `login_callout` never cancelled when `sbp_dev` is freed → use-after-free (hostile FireWire device)

## Where
`sys/dev/disk/sbp/sbp.c`

- Arming: `sbp_login()` `callout_reset(&sdev->login_callout, ticks<=login_delay(1000ms), sbp_login_callout, sdev)` — sbp.c:649-650; called from `sbp_probe_target` (sbp.c:692-693, `auto_login=1` default) for every LUN in `SBP_DEV_RESET`.
- Free paths with **no** `callout_stop(&sdev->login_callout)`:
  - `sbp_alloc_lun()` stale-LUN invalidation: `sbp_cam_detach_sdev(sdev); sbp_free_sdev(sdev);` — sbp.c:444-445 (LUN dropped from the device's Config ROM),
  - `sbp_alloc_lun()` trailing `!VALID_LUN` loop — sbp.c:534-541,
  - `sbp_post_explore()` GC: `sbp_cam_detach_target(target); sbp_free_target(target);` — sbp.c:776-786, and `num_lun==0` — sbp.c:816-817, both reaching `sbp_free_sdev` — sbp.c:1978-1990 (kfree at :1989, no callout handling).
  Only `sbp_logout_all` (sbp.c:1959, shutdown/detach) stops it.
- Fire: `sbp_login_callout` (sbp.c:625-629) → `sbp_mgm_orb(sdev, ORB_FUN_LGI, NULL)` on the freed `sdev`: reads `sdev->target`, `sbp_get_ocb(sdev)` walks `sdev->free_ocbs` (freed slab), then writes `ocb->flags`, `ocb->orb[0..7]` into `fwdma_free`'d ORB pages and re-arms `target->mgm_ocb_timeout` with the freed ocb — UAF read+write of kernel heap.

## Threat model
A crafted/hostile FireWire device fully controls its Config ROM (CROM_LUN set)
and bus-reset timing (any node can force a bus reset). Sequence: present LUN
N → probe arms `login_callout` (up to 1 s) → force bus reset and re-appear
without LUN N → `sbp_post_explore` → `sbp_alloc_lun` frees LUN N's `sdev`
while armed → callback fires ≤1 s later on freed memory. Deterministic,
attacker-timed.

## Evidence in this pack
- `sbp_replica.c` mechanism A (built & run on the audit guest, `build.log`/`run.log`): proves the DragonFly callout subsystem fires the callback on a kfree'd container — `sbpprep[A]: login_callout FIRED on FREED object 0xfffff80117817880` — reproduced on two independent boots.
- `env.txt`: guest has no FireWire OHCI hardware → end-to-end trigger not runnable on this guest (status inconclusive, mechanism proven).
- `VERDICT.md`: full path:line analysis.
- `fix.diff`: one-line `callout_stop` restoration in `sbp_free_sdev` (+ scan_callout in `sbp_free_target`).

## Reproduce
```
# on the DFly guest with /usr/src:
cd /root/kmod && make && kldload ./sbpprep.ko
sysctl kern.sbpprep_a=1      # arm + immediate kfree of container
sleep 4; dmesg | grep 'sbpprep\[A\]'
# expect: "...login_callout FIRED on FREED object 0x... (arg == freed pointer: YES)"
```
(For the DF-3982 sibling mechanism in the same module see `../DF-3982/`.)
