The pass(4) driver's CAMIOCOMMAND and CAMIOQUEUE ioctls accept
arbitrary CCBs from userland. Previously, the only func_code filter
was a blocklist check against the XPT_FC_XPT_ONLY flag. This missed
several dangerous func_codes that lack that flag:
- XPT_ABORT: the abort_ccb field is a raw kernel pointer from the user CCB payload. xpt_action_default() dereferences it without validation, leading to kernel crashes or worse.
- XPT_SASYNC_CB: the callback and callback_arg fields come directly from the user CCB payload and get registered as a kernel async callback, allowing arbitrary kernel code execution.
- Target mode CCBs (XPT_EN_LUN, XPT_TARGET_IO, etc.) fall through directly to the SIM with user-controlled payloads.
Replace the XPT_FC_XPT_ONLY blocklist with an explicit allowlist of CCB
function codes that are known to be safe for userland to submit: I/O
operations (SCSI, ATA, NVMe, SMP, MMC), device queries, transport
settings, and a handful of safe control operations (NOOP, REL_SIMQ,
RESET_DEV, DEBUG). Normally, the /dev/pass* permissions only allow root
to access them, so this is only a safety issue by default.
Also reject CAM_DATA_PADDR and CAM_DATA_SG_PADDR, since these pass
user-supplied physical addresses directly to DMA with no validation,
which on systems without an IOMMU allows arbitrary host memory access.
Add options PASS_UNSAFE_PADDR to allow the old behavior.
Verified that camdd, camcontrol, smartmontools, and cdrtools use only
func_codes on the allowlist (XPT_SCSI_IO, XPT_ATA_IO, XPT_NVME_IO,
XPT_NVME_ADMIN, XPT_PATH_INQ, XPT_GDEV_TYPE, XPT_GET_TRAN_SETTINGS,
XPT_SET_TRAN_SETTINGS, XPT_RESET_DEV, XPT_DEBUG) and none use
CAM_DATA_PADDR.
PR: 293888, 293890
Assisted-By: Claude Opus 4.6 (1M context)
Sponsored by: Netflix