Unvalidated FCP response/sense lengths cause OOB read from kernel stack (24XX FC)
Summary
isp_intr 24XX FC response-queue path: rlen=((isp24xx_statusreq_t*)sp)->req_response_len read from firmware DMA without validation (isp.c:5225). snsp=((isp24xx_statusreq_t*)sp)->req_rsp_sense; snsp+=rlen at :5238-5240 - req_rsp_sense[28] is last field of 64-byte stack qe[QENTRY_LEN]. If rlen>=28, snsp points past qe. XS_SAVE_SENSE at :5307-5308 memcpy(&xs->sense_data, snsp, imin(32, slen)) reads up to 32 bytes from wild pointer. Remote FC target sends FCP_RSP IU with FCP_RSP_LEN>=28 -> kernel panic (unmapped page) or kernel stack info leak via CAM autosense. No auth needed beyond FC fabric presence. Fix: clamp rlen to sizeof(req_rsp_sense) and slen to sizeof(req_rsp_sense)-rlen.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-1125 Β· 12 files| File | Type | Description | Size | |
|---|---|---|---|---|
| harness.c | trigger-source | userspace replica of isp.c 24XX FCP response/sense arithmetic + WITH-FIX pass | 6.9 KB | view raw |
| build.sh | build-script | cc -O2 -Wall -Wextra -o harness harness.c | 114 B | view raw |
| run.sh | run-script | ./harness | 60 B | view raw |
| build.log | build-log | final build, full output | 8 B | view raw |
| run.log | run-log | decisive run incl CONFIRMED + FIX VALIDATED | 1.7 KB | view raw |
| env.txt | environment | uname, cc, pciconf (no FC HW) | 241 B | view raw |
| fix.diff | suggested-fix | clamp rlen<=28 and slen<=28-rlen in isp.c | 1.4 KB | view raw |
| fix_validation.txt | fix-validation | apply-check + compile (rc=0) + harness fix-demo | 1.7 KB | view raw |
| VERDICT.md | verdict | full narrative | 2.9 KB | β raw |
| README.md | readme | summary + repro | 2.6 KB | β 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 |
DF-1125 β isp 24XX FCP response/sense length OOB read
Verdict
CONFIRMED (source-trace + harness) β INCONCLUSIVE on-guest (HW-gated). The bug is real; it cannot be triggered on the audit QEMU guest because the guest has no QLogic 24XX Fibre Channel HBA and no FC fabric (virtio net/display only).
Bug (one line)
isp_handle_intr_response() reads req_response_len straight from firmware DMA
and does snsp = req_rsp_sense + rlen without clamping; req_rsp_sense[28] is the
last field of the 64-byte stack queue entry, so any rlen >= 28 drives snsp
past the entry, and XS_SAVE_SENSE memcpy()s up to 32 bytes from the wild pointer.
Mechanism (path:line)
sys/dev/disk/isp/isp.c:5042βuint8_t qe[QENTRY_LEN];(QENTRY_LEN = 64), a stack buffer;sp = (isp24xx_statusreq_t *)qe.ispmbox.h:654-668βisp24xx_statusreq_tis exactly 64 bytes;req_rsp_sense[28]is the final field (offset 36), filling the entry to the boundary.isp.c:5225βrlen = sp->req_response_len;(read from firmware DMA, unvalidated).isp.c:5238-5240βsnsp = sp->req_rsp_sense; snsp += rlen; slen = sp->req_sense_len;with no bound;rlen >= 28=>snsp >= qe+64.isp.c:5307-5308βXS_SAVE_SENSE(xs, snsp, slen)=>isp_freebsd.h:483memcpy(&xs->sense_data, snsp, imin(XS_SNSLEN, slen))reads up to 32 bytes from the wild pointer.
Trigger / threat model
A remote Fibre Channel target sending an FCP_RSP IU with FCP_RSP_LEN (mapped to
req_response_len) >= 28. amdgpu_ucode_validate-class guards do not apply; there
is no length validation anywhere on the 24XX path. Small rlen => kernel stack
info leak into CAM autosense (readable via REQUEST SENSE); large rlen => panic
from unmapped page. CVSS AV:A (adjacent fabric), no auth beyond fabric presence.
Reproduction on the audit guest
Not possible β no QLogic 24XX FC HBA on the QEMU guest. harness.c is a faithful
userspace replica of the kernel arithmetic, built and run as the unprivileged
maxx user. It proves the OOB read primitive concretely and also runs the fixed
(clamped) logic to show 0 OOB remain.
Build / run
cc -O2 -Wall -Wextra -o harness harness.c # build.sh ./harness # run.sh
Expected: DF-1125: CONFIRMED OOB read primitive then
DF-1125 FIX: VALIDATED - clamps eliminate all OOB reads.
Fix
fix.diff clamps rlen to sizeof(req_rsp_sense) (28) and slen to
sizeof(req_rsp_sense) - rlen so snsp + slen cannot exceed the entry. Applies
cleanly (git apply --check OK); compiles in the GENERIC kernel build (rc=0).
DF-1125 β VERDICT
Verdict: CONFIRMED via source-trace + userspace harness. On-guest: INCONCLUSIVE (HW-gated β no QLogic 24XX FC HBA on the QEMU guest).
Root-cause confirmation
The bug is unambiguous in the audited source. The 24XX (QLogic FC) response-queue
path in isp_handle_intr_response() consumes two lengths β req_response_len and
req_sense_len β directly from firmware DMA with no validation, then performs
pointer arithmetic snsp = sp->req_rsp_sense + rlen where req_rsp_sense[28] is the
final field of a 64-byte stack queue entry (uint8_t qe[QENTRY_LEN] at
isp.c:5042). Because isp24xx_statusreq_t is exactly 64 bytes (ispmbox.h:654-668),
any firmware-supplied rlen >= 28 advances snsp to/past the end of qe. The
subsequent XS_SAVE_SENSE(xs, snsp, slen) (isp.c:5307) expands to
memcpy(&xs->sense_data, snsp, imin(XS_SNSLEN, slen)) (isp_freebsd.h:483),
reading up to 32 bytes from the wild pointer into CAM autosense.
Evidence
harness.c(run as unprivilegedmaxxon the audit guest) replicates the exact arithmetic and shows that 7/7 firmware-controlledrlenvalues (includingrlen=28, the boundary) read past the 64-byte entry; a leak demo copies 32 bytes of an adjacent-stack canary (all0xA1) into the "sense" buffer β a kernel-stack info leak of up to 32 bytes (and, for largerlen, a guaranteed unmapped-page panic).- Full run:
run.log. Build:build.log. Environment (no FC HW):env.txt.
Exploit chain / impact
This is an OOB read (CWE-125), not a write primitive, so there is no escalation
chain to uid=0. Realistic impact ceiling: kernel stack info leak up to 32 bytes
(sufficient for KASLR/text-pointer defeat and stack-residue disclosure) when a
malicious FC target chooses a small rlen; a large rlen yields a panic (DoS)
from an unmapped page. AV:A, no auth beyond FC fabric presence.
Fix validation
fix.diff clamps rlen to sizeof(req_rsp_sense) (28) and slen to
sizeof(req_rsp_sense) - rlen at the two points the lengths enter use.
- git apply --check -p1 => OK.
- Compiles in the GENERIC kernel build (full nativekernel, rc=0; isp.o built clean).
- Harness "WITH FIX" pass: 0/7 OOB cases remain.
- Boot-test of the stripped patched kernel could not complete (loader-format artifact
on kernel.stripped, unrelated to the fix); the bug path is HW-gated regardless.
- fix_status: not_testable (HW-gated runtime; apply-check + compile + harness fix-demo + trace all pass).
PoC changes
The evidence pack was authored from scratch (the seeded dir was empty): harness.c
(userspace replica of the kernel path + a "WITH FIX" pass), build.sh, run.sh,
fix.diff (git-apply-able), VERDICT.md, manifest.json, full logs.
Kernel refs (confirmed during verification)
sys/dev/disk/isp/isp.c:5042, :5225, :5238, :5239, :5240, :5307;
sys/dev/disk/isp/ispmbox.h:654-668, :290 (QENTRY_LEN); sys/dev/disk/isp/isp_freebsd.h:480-484.
Fix verification
not_testablecompile+harness validated
module build rc=0 + harness 0 OOB
Confirmed kernel references
β
Detail
Exploit chain
none
Evidence (decisive lines)
β
Verdict
Source-confirmed+harness. isp_handle_intr_response rlen unvalidated -> snsp OOB -> 32B stack info leak. No QLogic FC HBA.
No comments yet.