# DF-3574 — sym_action2 lacks target/LUN bounds validation before indexing np->target[] / lunmp[]

File: `sys/dev/disk/sym/sym_hipd.c` (pass 2, GLM 5.3 re-audit)

## What

`sym_action2()` handles `XPT_SET_TRAN_SETTINGS` and `XPT_GET_TRAN_SETTINGS` by
indexing driver tables directly from the CCB header:

* sym_hipd.c:8048  `tp = &np->target[ccb_h->target_id];`          (SET)
* sym_hipd.c:8054  `lp = sym_lp(np, tp, ccb_h->target_lun);`      (SET)
* sym_hipd.c:8076  `tp = &np->target[ccb_h->target_id];`          (GET)
* sym_hipd.c:8077  `lp = sym_lp(np, tp, ccb_h->target_lun);`      (GET)

`sym_lp()` (sym_hipd.c:1269-1271) expands to `tp->lunmp[(lun)]` for any
non-zero LUN.  `np->target[]` has `SYM_CONF_MAX_TARGET` (16) entries and
`lunmp[]` has `SYM_CONF_MAX_LUN` (64) pointer entries.

The SCSI-IO entry point `sym_action()` *does* validate
(sym_hipd.c:7501-7506), as does `sym_reset_dev()` (sym_hipd.c:7438-7443).
`sym_action2()` has **no equivalent check**.  A CCB carrying
`target_id >= 16` (or a wildcard `0xFF`/`0xFFFF`) would read out of bounds;
the GET path copies the out-of-bounds `tinfo`/`usrflags` bytes back into the
`ccb_trans_settings` returned to the caller (kernel-memory info leak of a few
bytes), and a wildcard LUN indexes `lunmp[0xFFFF]` — an OOB read 512 KB past
the array whose result is dereferenced (`lp->current_flags`,
sym_hipd.c:8083/8087) — wild pointer dereference.

## Reachability (why this is Info / speculative)

Every currently-reachable delivery path was traced in this audit:

1. `pass(4)` CAMIOCOMMAND — `xpt_merge_ccb()` does not copy `target_id` /
   `target_lun` from the user CCB; they are set by `xpt_setup_ccb()`
   (cam_xpt.c:3911-3918) from the *periph path*, i.e. a real discovered
   device (target 0..15, lun 0..63 on sym).
2. `/dev/xpt0` CAMIOCOMMAND only accepts SCAN_BUS/RESET_BUS/PATH_INQ/
   ENG_INQ/SCAN_LUN/DEBUG (cam_xpt.c:1028-1050) — never TRAN_SETTINGS.
3. `XPT_SET_TRAN_SETTINGS` is intercepted by `xpt_set_transfer_settings()`
   (cam_xpt.c:3051-3056) and re-issued on the same (real-device) path.
4. The internal wildcard-LUN path created by the driver itself
   (`sym_xpt_async_transfer_neg`, sym_hipd.c:3454) only feeds
   `xpt_async(AC_TRANSFER_NEG)` → `xpt_set_transfer_settings(..., async_update=TRUE)`,
   which skips both the XPT_GET_TRAN_SETTINGS round-trip and the direct
   `sim_action()` call (cam_xpt.c: tail of xpt_set_transfer_settings).
5. Phantom targets created by `xpt_compile_path()` (DragonFly's version does
   NOT wildcard-guard target/lun — cam_xpt.c:3973-4045 — unlike FreeBSD)
   never get past the probe INQUIRY because `sym_action()` rejects the
   SCSI_IO with CAM_DEV_NOT_THERE, so no TRAN_SETTINGS CCB follows.

So today the missing check is *latent*: no constructible path delivers an
out-of-range target/lun to `sym_action2()`.  It is filed as defense-in-depth
(the neighbouring entry points all validate; any future CAM change — e.g. a
new sender of TRAN_SETTINGS on wildcard paths — would turn this into an OOB
read/info leak).

## PoC

Not runnable: the trigger path does not exist today, and the guest has no
Symbios/LSI 53C8xx PCI HBA (virtio only), so the driver cannot even attach.
Source-level verification only.  See VERDICT.md.

## Fix

`fix.diff` — add the same bounds check `sym_action()` uses to the two
TRAN_SETTINGS cases (not a blanket early return: XPT_RESET_BUS legally
arrives with wildcard target from `/dev/xpt0`).
