β¬’ DragonFlyBSD Kernel Audit
← triage Β· dashboard
DF-3676

mpt_abort_target_ccb indexes trt[target_lun] without the MPT_MAX_LUNS guard every sibling target-mode XPT case has

Summary

XPT_ABORT (reachable via pass(4)) lands in mpt_abort_target_ccb, which picks trt[ccb->ccb_h.target_lun] with no bounds check, unlike the identical pattern guarded elsewhere in the file. trt[] has 256 entries; a LUN in [256, CAM_LUN_WILDCARD) would OOB-read a tgt_resource_t and STAILQ_REMOVE from it. Currently unreachable with OOB values (pass paths enumerated up to max_lun=256) - SIM-boundary defense-in-depth matching the sym(4) DF-3574 Info precedent. Latent: any future producer of high-LUN paths turns this into an OOB list removal.

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-3676 Β· 6 files
FileTypeDescriptionSize
README.md β€” 399 B ↓ raw
VERDICT.md β€” 2.7 KB ↓ raw
fix.diff β€” 587 B view raw
env.txt β€” 281 B view raw
verdict.json β€” 1.6 KB view raw
manifest.json β€” 471 B view raw

DF-3676 β€” mpt_abort_target_ccb indexes trt[lun] without the bounds guard every sibling XPT case has

Severity: Info (defense-in-depth; no currently-reachable producer of LUN >= 256). mpt_cam.c:4631-4635 vs the guard at 3683-3693. trt[] has 256 entries (mpt.h:367,709). Pattern precedent: sym(4) DF-3574 (Info). Fix in fix.diff. No runtime PoC (hardware-gated; guest has no MPT HBA β€” env.txt).

VERDICT.md
↓ download raw

DF-3676 β€” VERDICT

status: inconclusive (hardening gap; currently unreachable with OOB values; no MPT hardware on guest)

Root cause

Every mpt XPT case that indexes mpt->trt[lun] validates the LUN first β€” except the abort path:

/* sys/dev/disk/mpt/mpt_cam.c:3683-3693 (XPT_{NOTIFY_ACK,IMMED_NOTIFY,ACCEPT_TARGET_IO}) */
        if (lun == CAM_LUN_WILDCARD) {
            ...
        } else if (lun >= MPT_MAX_LUNS) {
            mpt_set_ccb_status(ccb, CAM_REQ_INVALID);   /* <-- guard */
            break;
        } else {
            trtp = &mpt->trt[lun];
        }
/* sys/dev/disk/mpt/mpt_cam.c:4631-4635 (XPT_ABORT -> mpt_abort_target_ccb) */
    if (ccb->ccb_h.target_lun == CAM_LUN_WILDCARD) {
        trtp = &mpt->trt_wildcard;
    } else {
        trtp = &mpt->trt[ccb->ccb_h.target_lun];   /* <-- no MPT_MAX_LUNS check */
    }

trt[] has MPT_MAX_LUNS = 256 entries (mpt.h:367, mpt.h:709). A LUN in [256, CAM_LUN_WILDCARD) reads tgt_resource_t (two STAILQ heads + int) out of bounds and STAILQ_REMOVEs from it (mpt_cam.c:4645-4651) β€” list corruption.

Reachability today (why Info, not Medium)

XPT_ABORT reaches mpt_action from userland via pass(4) (XPT_ABORT lacks XPT_FC_XPT_ONLY β€” cam_ccb.h:143), but the abort CCB's path LUN is the pass device's enumerated LUN, and CAM scans LUNs only up to cpi->max_lun = MPT_MAX_LUNS (mpt reports 256 at mpt_cam.c:3598-3599; SPI: 7). So no currently-reachable producer hands mpt a path LUN β‰₯ 256. The check is nevertheless required at the SIM boundary because (a) CAM does not enforce it centrally, (b) any future caller (xpt ioctl extension, in-kernel periph) can construct arbitrary-LUN paths, and (c) the file's own convention β€” every sibling case guards. This mirrors the sym(4) DF-3574 pattern filed as Info.

Fix

--- a/sys/dev/disk/mpt/mpt_cam.c
+++ b/sys/dev/disk/mpt/mpt_cam.c
@@ -4628,8 +4628,12 @@ mpt_abort_target_ccb(struct mpt_softc *mpt, union ccb *ccb)
    mpt_lprt(mpt, MPT_PRT_DEBUG, "aborting ccb %p\n", accb);

-   if (ccb->ccb_h.target_lun == CAM_LUN_WILDCARD) {
+   if (ccb->ccb_h.target_lun == CAM_LUN_WILDCARD) {
        trtp = &mpt->trt_wildcard;
-   } else {
+   } else if (ccb->ccb_h.target_lun < MPT_MAX_LUNS) {
        trtp = &mpt->trt[ccb->ccb_h.target_lun];
+   } else {
+       return (CAM_LUN_INVALID);
+   }

Guest verdict

inconclusive (hardware-gated even for the benign reachability demo); source-level gap certain.

Fix status (batch validation)

Applied with the 36 sibling fix.diffs of this batch in findings/poc/_batch41/all_fixes.patch; single in-guest make -j6 nativekernel KERNCONF=X86_64_GENERIC completed RC=0 with zero errors under -Werror (full log: findings/poc/_batch41/fix_build8.log). Behavior A/B intentionally skipped for this Info-tier item.

Fix verification

not_testable
baseline no→ patch + rebuild →patched clean

Guard diff authored (fix.diff); not exercisable without hardware.

fix.diff; env.txt
↓ fix.diffper-fix-DF-3676

Confirmed kernel references

Detail

Evidence (decisive lines)

VERDICT.md (guard asymmetry with path:line); fix.diff; env.txt

PoC changes

n/a

Verified recommended fix

Add 'else if (lun < MPT_MAX_LUNS)' with CAM_LUN_INVALID return in mpt_abort_target_ccb

Verdict

Hardening gap (Info): mpt_abort_target_ccb indexes mpt->trt[ccb->ccb_h.target_lun] with no MPT_MAX_LUNS check (mpt_cam.c:4631-4635) while every sibling target-mode XPT case guards lun >= MPT_MAX_LUNS (mpt_cam.c:3683-3693, 4298, 4324). trt[] is 256 entries. Today no reachable producer hands mpt a path LUN >= 256 (pass paths are enumerated up to cpi->max_lun=256), so this is defense-in-depth at the SIM boundary, matching the sym DF-3574 precedent. Not executable on this guest (no MPT hardware).