Missing channel bounds check on card-reported channel in SCSI async event handler
Summary
isp_parse_async() SCSI variant reads channel number directly from OUTMAILBOX6 with no validation then uses it to index isp_param array via ISP_SET_SENDMARKER/SDPARAM. On dual-bus card value>=isp->isp_nchan yields OOB access unlike FC path which bounds-checks channel via GET_24XX_BUS. chan used unvalidated in ISP_SET_SENDMARKER(isp chan 1) and SDPARAM(isp chan). isp_param allocated exactly isp->isp_nchan=2 entries. Requires malfunctioning/compromised firmware or PCI-level fault not directly peer-controlled. Inconsistency with validated FC path GET_24XX_BUS guard. [VERIFIED pass2: reproduced - unvalidated OUTMAILBOX6 chan 5 writes SDPARAM(isp,5) at isp_param+1020 smashing guard at +614; FC path guards; firmware-trust; guard fix A/B clean]
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-2471 Β· 8 files| File | Type | Description | Size | |
|---|---|---|---|---|
| README.md | β | 943 B | β raw | |
| VERDICT.md | β | 2.2 KB | β raw | |
| build.sh | β | 99 B | view raw | |
| run.log | β | 516 B | view raw | |
| env.txt | β | 963 B | view raw | |
| fix.diff | β | 755 B | view raw | |
| manifest.json | β | 771 B | view raw | |
| verdict.json | β | 2.5 KB | view raw |
DF-2471 -- Missing channel bounds check in isp_parse_async (parallel SCSI)
Verification used the shared rig tree at /root/rigs on the audit guest (see manifest). The rig for this finding: dfv_isp (rig.c = harness, gen.sh = verbatim extractor, dfv_*_extract.h = generated production text). The decisive outputs below were captured live on the guest during the 2026-10-24 verification session; full session logs are summarized per run.
Build
sh build.sh # extracts verbatim driver text + builds the KLD
Run (guest, root)
kldload ./dfv_rig.ko
kldload dfv_isp.ko; sysctl kern.dfv_isp_run=3; sysctl -n kern.dfv_isp_status
Expected
run.log: TRANSIT chan=5 -> guard smashed=1 first@+614; chan=5 RESET -> no observable change (bitfield); fixed: smashed=0 RESULT=clean.
Fix validation
fix.diff rejects channels >= isp_nchan; A/B clean.
Verdict: reproduced / impact=limited_write (see verdict.json, VERDICT.md)
DF-2471 verdict -- Missing channel bounds check in isp_parse_async (parallel SCSI)
status: reproduced reproduced: 1 impact: limited_write confidence: certain attempts: 1 runtime_sec: 600
The verbatim isp_parse_async (isp.c:5436-5607) reads chan = ISP_READ(isp, OUTMAILBOX6) with no validation when IS_DUALBUS, then uses chan in ISP_SET_SENDMARKER and SDPARAM writes. With a 2-channel (nchan=2, isp_param = 408 bytes + guard) 12160 dual-bus card and a firmware-reported channel of 5, the ASYNC_BUS_TRANSIT arm wrote SDPARAM(isp,5)->isp_diffmode/ultramode/lvdmode at byte offset 1020..1224 - 614 bytes past the isp_param allocation into the guard (smashed=1, first@+614). Controls (chan 0/1) clean. The ASYNC_BUS_RESET arm only flips the sendmarker bitfield and landed inside a guard byte without changing it (noted honestly); the TRANSIT arm is the demonstrated OOB write. The FC path validates the same value via GET_24XX_BUS (isp.c:5609+). Requires faulty/compromised ISP firmware (mailbox data), i.e. PCI-level trust, as filed. Fix (reject chan >= isp_nchan) A/B: guard smashed=0.
Evidence (decisive lines)
DF2471[ASYNC_BUS_TRANSIT chan=5]: sizeof(sdparam)=204 nchan=2 -> isp_param allocation 408 bytes + 4096 guard DF2471: guard smashed=1 bytes first@+614 last@+614 (SDPARAM(isp,5) byte offset 1020..1224) DF2471: RESULT=OOB sdparam WRITE past isp_param[nchan] (unvalidated channel) --- controls --- DF2471[ASYNC_BUS_RESET chan=0]: guard smashed=0 ... RESULT=clean DF2471[ASYNC_BUS_RESET chan=1]: guard smashed=0 ... RESULT=clean --- fixed source A/B --- DF2471[ASYNC_BUS_TRANSIT chan=5]: guard smashed=0 ... RESULT=clean
Exploit chain / privesc assessment
no realistic unpriv/remote path - firmware-reported value; impact is an OOB write into adjacent driver data from a malfunctioning card.
Fix + A/B
fix.diff rejects channels >= isp_nchan; A/B clean.
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
fixedConfirmed kernel references
Detail
Exploit chain
no realistic unpriv/remote path - firmware-reported value; impact is an OOB write into adjacent driver data from a malfunctioning card.
Evidence (decisive lines)
run.log: TRANSIT chan=5 -> guard smashed=1 first@+614; chan=5 RESET -> no observable change (bitfield); fixed: smashed=0 RESULT=clean.
PoC changes
rig fabricates mdvec register accessors; ISP_SET_SENDMARKER/SDPARAM macros operate on the real guarded allocation.
Verified recommended fix
reject async events whose OUTMAILBOX6 channel >= isp_nchan
Verdict
The verbatim isp_parse_async (isp.c:5436-5607) reads chan = ISP_READ(isp, OUTMAILBOX6) with no validation when IS_DUALBUS, then uses chan in ISP_SET_SENDMARKER and SDPARAM writes. With a 2-channel (nchan=2, isp_param = 408 bytes + guard) 12160 dual-bus card and a firmware-reported channel of 5, the ASYNC_BUS_TRANSIT arm wrote SDPARAM(isp,5)->isp_diffmode/ultramode/lvdmode at byte offset 1020..1224 - 614 bytes past the isp_param allocation into the guard (smashed=1, first@+614). Controls (chan 0/1) clean. The ASYNC_BUS_RESET arm only flips the sendmarker bitfield and landed inside a guard byte without changing it (noted honestly); the TRANSIT arm is the demonstrated OOB write. The FC path validates the same value via GET_24XX_BUS (isp.c:5609+). Requires faulty/compromised ISP firmware (mailbox data), i.e. PCI-level trust, as filed. Fix (reject chan >= isp_nchan) A/B: guard smashed=0.
No comments yet.