# DF-5240 evidence pack

## Finding
`xpt_scan_bus()` (sys/bus/cam/cam_xpt.c, case XPT_SCAN_BUS create-path
failure branch, lines 5387-5398) frees the **in-flight XPT_SCAN_LUN CCB**
(`work_ccb` has already been reassigned to the SCAN_LUN CCB issued for
target 0) and `scan_info` (still referenced via `ccb_h.ppriv_ptr0` by every
issued SCAN_LUN CCB) when `xpt_create_path()` fails mid-loop. The probe
peripheral later completes the freed CCB; the SWI callback `xpt_scan_bus()`
case XPT_SCAN_LUN then runs `xpt_setup_ccb()` on it → `callout_init(NULL)`
(write to 0x10) → kernel page fault. With the freed chunk reclaimed, the
completion also writes `scan_info->counter--` and dereferences the dangling
`scan_info->cpi`.

Precondition (race): a parallel-mode bus scan (`hba_misc & PIM_SEQSCAN == 0`)
racing SIM deregistration — e.g. USB umass unplug during the boot scan, or
`camcontrol rescan` racing device detach (`xpt_alloc_device()` returns NULL
once `CAM_SIM_DEREGISTERED` is set, cam_xpt.c:5083).

## Contents
- `evilsim.c`, `Makefile` — kld PoC: fake SIM + choreography (stall first
  INQUIRY of target 0, mark SIM deregistered → scan loop's create_path for
  target 1 fails → buggy free; spray freed `scan_info` with 0x41; complete
  the stalled INQUIRY → panic).
- `build.sh` / `run.sh` — exact commands (build kld, kldload as root).
- `build.log` — full compiler output (rc=0).
- `run.log` — the decisive run (markers + Fatal trap, from the vm.sh guest).
- `panic.txt` — serial console with the DDB `trace` backtrace
  (`_callout_init ← xpt_setup_ccb ← xpt_scan_bus ← camisr_runqueue`).
- `panic.notrace.txt` — earlier run without trace (same fault).
- `fix.diff` — git-apply-able fix (validated: kernel rebuilt with it, PoC
  no longer panics — see VERDICT.md).
- `env.txt` — guest uname/sysctl/toolchain.

## Reproduce
```
# guest (root), after pushing evilsim.c + Makefile to /root/df5240
cd /root/df5240 && make
kldload ./evilsim.ko          # kernel panics within seconds
dmesg / serial console: "Fatal trap 12 ... Stopped at _callout_init"
```
Interactive variant for the DDB backtrace: run QEMU with
`-serial unix:...,server` (or stdio), `sysctl debug.trace_on_panic` is not
needed — DDB stops at the trap; type `trace`.

Expected output markers:
```
[EVILSIM] stalled INQUIRY for target 0 lun 0, SIM marked DEREGISTERED
xpt_scan_bus: xpt_create_path failed with status 0x34, bus scan halted
[EVILSIM] back from XPT_SCAN_BUS: stall_seen=1 ...
[EVILSIM] sprayed 128 x 24-byte chunks with 0x41 ...
[EVILSIM] completing stalled INQUIRY -> expect page fault ... NOW
Fatal trap 12: page fault ... supervisor write data
Stopped at      _callout_init:  movq    $0,0x10(%rdi)
```

## Fix validation
`vm.sh reset with-src`; `git apply fix.diff` in guest /usr/src;
`make -j6 nativekernel KERNCONF=X86_64_GENERIC && make installkernel`;
reboot; re-run the exact PoC: **no trap** — scan halts with the marker
message, guest stays up, module unloads cleanly.
