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

Heap overflow in isp_handle_platform_atio CDB copy (parallel SCSI target mode)

Summary

isp_handle_platform_atio at isp_freebsd.c:1926-1927: ISP_MEMCPY(atiop->cdb_io.cdb_bytes, aep->at_cdb, aep->at_cdblen) copies firmware-reported at_cdblen (uint8 0..255) into cdb_bytes[IOCDBLEN=16]. Source at_cdb[ATIO_CDBLEN=26]. No clamp. at_cdblen>16 overflows cdb_bytes into cdb_len/tag_action/sense_len/tag_id/init_id fields. FC sibling paths atio2/atio7 use fixed ATIO2_CDBLEN=16/sizeof(fcp_cmnd_cdb)=16. Requires ISP_TARGET_MODE option (not default) AND parallel-SCSI QLogic HBA. Attacker: device on parallel SCSI bus or SCSI-passthrough VM. Fix: clamp to min(at_cdblen, sizeof(cdb_bytes)).

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-1155 Β· 8 files
FileTypeDescriptionSize
VERDICT.md verdict Full source trace + 3-layer reachability analysis 4.7 KB ↓ raw
fix.diff suggested-fix Clamp at_cdblen to sizeof(cdb_bytes) (git apply-able, validated) 581 B view raw
build.sh build-doc Documents why no executable PoC is possible 453 B view raw
run.sh run-doc Documents why runtime trigger is impossible on this guest 223 B view raw
env.txt environment uname + 3-layer unreachability proof (no symbol, no opt, no HBA) 558 B view raw
README.md readme human reproduce doc 940 B ↓ raw
../fix_build_combined.log build-log Combined 41-finding kernel build (rc=0, -Werror clean) 5.6 MB ↓ download
../fix_build_summary.txt build-summary Summary of the combined 41-finding kernel build 826 B view raw
README.md readme human reproduce doc
↓ download raw

DF-1155 β€” heap overflow in isp_handle_platform_atio CDB copy

Result

NOT REPRODUCED on this guest. Real source-level defense-in-depth bug; fix authored. See VERDICT.md for the full analysis.

Build & run

./build.sh    # documents why no executable PoC is possible
./run.sh      # documents why runtime trigger is impossible

Reachability summary (3 independent blockers)

  1. The vulnerable function isp_handle_platform_atio is not in the kernel binary β€” all callers are inside #ifdef ISP_TARGET_MODE, which is not defined; nm kernel.debug | grep -c isp_handle_platform_atio β‡’ 0.
  2. ISP_TARGET_MODE is opt-in only (LINT64, commented out) β€” not in X86_64_GENERIC.
  3. No QLogic parallel-SCSI HBA on the QEMU guest.

Fix

fix.diff β€” clamp at_cdblen to sizeof(cdb_bytes) (= IOCDBLEN = 16) at sys/dev/disk/isp/isp_freebsd.c:1926-1927. Applies cleanly with git apply.

VERDICT.md verdict Full source trace + 3-layer reachability analysis
↓ download raw

DF-1155 β€” heap overflow in isp_handle_platform_atio CDB copy

Verdict

NOT REPRODUCED on this guest (defense-in-depth source bug confirmed; path unreachable on the default GENERIC DragonFlyBSD kernel running in QEMU). Real source-level defect; fix.diff authored.

Mechanism (source trace, bug confirmed real)

In sys/dev/disk/isp/isp_freebsd.c:1829, isp_handle_platform_atio() copies a SCSI CDB delivered by the QLogic firmware into a CAM ccb_accept_tio:

/* sys/dev/disk/isp/isp_freebsd.c:1925-1927 */
atiop->init_id  = GET_IID_VAL(aep->at_iid);
atiop->cdb_len  = aep->at_cdblen;                                          /* L1926 */
ISP_MEMCPY(atiop->cdb_io.cdb_bytes, aep->at_cdb, aep->at_cdblen);          /* L1927 */

The sizes are mismatched and there is no clamp:

Object Field Size Source
source at_entry_t.at_cdb aep->at_cdb ATIO_CDBLEN = 26 sys/dev/disk/isp/ispmbox.h:1965,1980
length at_entry_t.at_cdblen aep->at_cdblen uint8_t β‡’ 0..255 sys/dev/disk/isp/ispmbox.h:1973
destination ccb_accept_tio.cdb_io.cdb_bytes atiop->cdb_io.cdb_bytes IOCDBLEN = CAM_MAX_CDBLEN = 16 sys/bus/cam/cam.h:53, sys/bus/cam/cam_ccb.h:44

The firmware-reported at_cdblen (0..255) is fed directly to ISP_MEMCPY without clamping to the destination size. A malicious firmware (or hostile device on a parallel SCSI bus, or a SCSI-passthrough VM) reports at_cdblen > 16 β‡’ the copy overruns cdb_bytes[16] into the subsequent fields of struct ccb_accept_tio (cdb_len, tag_action, sense_len, tag_id, init_id, …) and beyond into adjacent slab memory. Per the finding, the FC siblings isp_handle_platform_atio2 (:1953) and isp_handle_platform_atio7 (:2126) use the fixed sizes ATIO2_CDBLEN = 16 / sizeof(fcp_cmnd_cdb) = 16, so they are not affected.

Why it does NOT reproduce on this guest

This finding has three independent reachability blockers, any one of which is fatal:

1. The vulnerable function is not in the kernel binary.

isp_handle_platform_atio is defined at isp_freebsd.c:1828-1950, which sits outside any #ifdef ISP_TARGET_MODE block. However every caller is inside such a block β€” the only entry point is the RQSTYPE_ATIO dispatch at isp_freebsd.c:5354-5359 inside the ISPASYNC_TARGET_ACTION case at :5334, which is inside the #ifdef ISP_TARGET_MODE block at :5263 (closed at :5431). Since ISP_TARGET_MODE is not defined by X86_64_GENERIC:

$ grep ISP_TARGET_MODE sys/config/X86_64_GENERIC
(empty)

the function has no callers, the compiler/linker drops it, and:

$ ssh dfbsd 'nm /boot/kernel/kernel.debug | grep -c isp_handle_platform_atio'
0

β‡’ confirmed: zero isp_handle_platform_atio symbols in the running kernel.

2. ISP_TARGET_MODE is opt-in, not default.

sys/conf/options:203 declares ISP_TARGET_MODE opt_isp.h. The only configuration that mentions it is sys/config/LINT64:1462 and it is commented out (#options ISP_TARGET_MODE=1). So even a custom kernel must explicitly opt in; default GENERIC and most production kernels do not enable target mode.

3. No parallel-SCSI QLogic HBA in the QEMU guest.

Even with ISP_TARGET_MODE enabled, the ISP driver only registers target mode for actual QLogic SCSI HBAs (1040/1080/12160/2100/2200/2300/2322 parallel SCSI; 2400/2500 FC). The QEMU guest has none of these on its virtual PCI bus β€” devinfo -v | grep -i qlogic is empty, and no isp controller attaches at probe. No firmware request queue β†’ no ATIO entry β†’ no path to the vulnerable function.

Exploit chain

none β€” primitive (kernel heap overflow) requires all three of: kernel built with ISP_TARGET_MODE, a QLogic SCSI HBA physically present (or SCSI-passthrough VM), and malicious firmware/device. None of these hold on the default GENERIC DragonFlyBSD guest.

PoC changes

none β€” no executable PoC is possible. Even building a custom ISP_TARGET_MODE=1 kernel would not help: the guest has no QLogic HBA, so the ISP driver would never call isp_handle_platform_atio. The function's only caller is the firmware-dispatch ISPASYNC_TARGET_ACTION path, which fires only when the HBA's request queue delivers an RQSTYPE_ATIO entry.

Clamp the copy length to the destination buffer size (16 bytes); also clamp the cdb_len recorded for the upper layer to the same value. See fix.diff β€” applies cleanly with git apply (validated). Matches the finding markdown's proposal.

The sibling FC paths (isp_handle_platform_atio2/atio7) are already safe because they use the fixed ATIO2_CDBLEN = 16 for both source and destination, so no parallel fix is needed there.

Fix verification

not_testable

git apply --check validated

see evidence pack

Confirmed kernel references

β€”

Detail

Exploit chain

none

Evidence (decisive lines)

β€”

Verdict

Source-confirmed. isp_handle_platform_atio CDB copy no clamp. ISP_TARGET_MODE not compiled, no QLogic HW.