# DF-5375 — no func_code whitelist in targwrite(): arbitrary queued XPT
# opcode injected by the daemon → deterministic targdone() panic

## What
`sys/bus/cam/scsi/scsi_target.c`

- `targwrite()` (:584-632) reads `func_code` from the *user* CCB via
  `fuword32()` and forwards ANY value to the CCB engine: ATIO/INOT get
  queued as target resources; every other code takes the default branch
  where only `XPT_FC_QUEUED` is inspected — queued codes go
  targstart→targusermerge→targsendccb→xpt_action, inline codes go
  straight to xpt_action.
- `targdone()` (:837-850) — the completion callback stamped on every
  forwarded CCB by `targsendccb()` (:769) — only expects
  XPT_IMMED_NOTIFY/XPT_ACCEPT_TARGET_IO/XPT_CONT_TARGET_IO and
  `panic("targdone: impossible xpt opcode %#x")` on the default case.
- So a daemon that writes an 8-byte pointer to a CCB with
  `func_code = XPT_SCSI_IO` (0x901, XPT_FC_DEV_QUEUED, cam_ccb.h:117)
  gets the CCB executed as an *initiator* I/O by the SIM and, when it
  completes, a guaranteed kernel panic. Same for XPT_SCAN_LUN,
  XPT_RESET_DEV, XPT_TRIM, XPT_ENG_EXEC, ...
- Secondary consequence of the same missing whitelist: opcodes whose
  payloads carry kernel pointers (XPT_SCSI_IO with CAM_CDB_POINTER
  cdb_io.cdb_ptr, data_ptr, DEV_MATCH cookies) are never validated or
  mapped — `targsendccb()` only maps CTIO/DEV_MATCH (:783-799) — so raw
  daemon-supplied kernel addresses are dereferenced by the SIM
  (CWE-822). FreeBSD's rewritten scsi_target.c restricts targwrite() to
  target-mode opcodes for exactly this reason.

## Rig
`targsim.c` kld: fake SIM with `target_sprt = PIT_PROCESSOR` so
TARGIOCENABLE succeeds; probe traffic answered so a device exists at
(bus,0,0); CCBs with `ccb_h.targ_descr != NULL` (i.e. forwarded by targ)
are completed CAM_REQ_CMP.

## Reproduce (guest, root; guest dies)
```
cd /root/targpwn
make KERNBUILDDIR=/usr/obj/usr/src/sys/X86_64_GENERIC   # targsim.ko
cc -O0 -g -o poc5375 poc5375.c
kldload ./targsim.ko; sleep 2
./poc5375
```

## Expected
`panic: targdone: impossible xpt opcode 0x901` on the serial console,
backtrace targdone <- camisr_runqueue <- swi_cambio. Guest dies (DDB).

## Files
- targsim.c / Makefile — target-capable fake SIM rig
- poc5375.c — trigger
- build.sh / build_poc.sh / run.sh
- build.log / run.log / panic.txt
- fix.diff — whitelist func codes in targwrite (EINVAL otherwise)
