Infinite loop in response queue processing when target mode consumes multiple entries
Summary
isp_intr at isp.c:5121-5124: while(tsto != oop) { optr = ISP_NXT_QENTRY(tsto, ...); }. Loop assigns to optr but NEVER modifies tsto or oop - condition is invariant. If initially true (isp_handle_other_response advanced tsto via target-mode ATIO7 long-IU continuation), unconditional infinite loop in hard interrupt context. Requires ISP_TARGET_MODE compiled (not default) and adapter in target role. Remote FC initiator sends Extended CDB/IU >56 bytes triggering long-IU path in isp_target_notify. Permanent kernel hang. Fix: change while to if.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-1126 Β· 11 files| File | Type | Description | Size | |
|---|---|---|---|---|
| harness.c | trigger-source | simulates queue pointers; proves loop body never advances tsto | 2.8 KB | view raw |
| fix.diff | suggested-fix | change while (tsto != oop) to if (tsto != oop) | 781 B | view raw |
| build.sh | build-script | cc -O2 -o harness harness.c | 95 B | view raw |
| run.sh | run-script | timeout 10 ./harness | 67 B | view raw |
| build.log | build-log | final successful build | 13 B | view raw |
| run.log | run-log | decisive run incl non-termination marker | 377 B | view raw |
| env.txt | environment | uname, cc version, pciconf (no ISP FC adapter) | 403 B | view raw |
| VERDICT.md | verdict | full narrative + ISP_TARGET_MODE gating discussion | 3.1 KB | β raw |
| README.md | readme | finding summary + build/run/expected | 1.5 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-1126 β Infinite loop in isp_intr response-queue processing (SCSI target mode)
Finding
isp_intr at sys/dev/disk/isp/isp.c:5121-5124:
while (tsto != oop) {
optr = ISP_NXT_QENTRY(tsto, RESULT_QUEUE_LEN(isp));
}
The loop body assigns to optr but never modifies tsto or oop β
the condition is invariant. isp_handle_other_response (:5113) passes
&tsto to isp_target_notify (isp_target.c:5988), which in the long-IU
continuation path (isp_target.c:178-181) advances *optrp (= tsto).
After return, tsto != oop and the loop spins forever in hard interrupt
context β permanent kernel hang.
Requires ISP_TARGET_MODE compiled (not default) and a target-mode FC
adapter receiving an Extended CDB/IU > 56 bytes from a remote initiator.
Reachability on this guest
NOT reachable. No QLogic ISP FC adapter present. ISP_TARGET_MODE is
not compiled into the default modules. Doubly gated. Latent.
A userspace harness demonstrates the invariant loop (capped at 1M iters to prove non-termination rather than actually hang).
Build / Run / Expected
cc -O2 -o harness harness.c # build.sh ./harness # run.sh # Expected: "LOOP DID NOT ADVANCE tsto -- infinite loop confirmed"
Files
harness.cβ simulates the queue bookkeeping; proves the loop body never advanceststo.fix.diffβ changeswhile (tsto != oop)toif (tsto != oop).build.log/run.log/env.txtβ captured outputs.
VERDICT β DF-1126
Verdict: REPRODUCED (primitive) / NOT REACHABLE on guest (HW-gated)
The cited bug is real and confirmed by source trace + userspace
loop-bookkeeping demonstration. It is a latent infinite-loop / hang
primitive requiring ISP_TARGET_MODE compiled (not default) and a
target-mode FC adapter receiving an Extended CDB/IU.
Mechanism (confirmed path:line)
isp_intr(sys/dev/disk/isp/isp.c:5112-5124) processes response queue entries. For unrecognized entry types it callsisp_handle_other_response(isp, etype, hp, &tsto)(:5113) wheretstois a local initialized tooop.isp_handle_other_response(:5964-6022) forRQSTYPE_ATIOetc. callsisp_target_notify(isp, hp, optrp)(:5988) inside#ifdef ISP_TARGET_MODE.isp_target_notify(sys/dev/disk/isp/isp_target.c:104) for anRQSTYPE_ATIO7(IS_24XX) with a long IU (at_ta_len > QENTRY_LEN-8) advances*optrpin a loop at:178-181:*optrp = ISP_NXT_QENTRY(*optrp, RESULT_QUEUE_LEN(isp)).- Back in
isp_intr:5121-5124:c while (tsto != oop) { optr = ISP_NXT_QENTRY(tsto, RESULT_QUEUE_LEN(isp)); }The body assigns tooptrbut never modifieststooroop. Afterisp_target_notifyadvancedtstopastoop, the condition is invariantly true β infinite spin in hard interrupt context β permanent kernel hang.
Reproduction (userspace harness)
The harness simulates the queue pointers, calls a stand-in for
isp_handle_other_response that advances tsto by one slot, then runs
the exact kernel loop body (capped at 1M iterations to prove
non-termination rather than actually hang):
oop = 100 tsto = 101 (advanced by isp_target_notify long-IU path) Hit iteration cap (1000000) without termination. tsto before loop = 101, tsto after = 101 (UNCHANGED) *** LOOP DID NOT ADVANCE tsto -- infinite loop confirmed ***
Impact ceiling
- Per-trigger: permanent kernel hang in hard interrupt context. The
CPU spinning in
isp_intrcannot be preempted; the system is wedged. - Privilege: remote β a FC initiator sending an Extended CDB/IU > 56
bytes triggers it. Requires target-mode FC adapter with
ISP_TARGET_MODE. - Realistic: doubly gated (
ISP_TARGET_MODEnot default + FC target role). Niche but remote-triggerable when configured.
Fix
fix.diff changes while to if:
if (tsto != oop) {
optr = ISP_NXT_QENTRY(tsto, RESULT_QUEUE_LEN(isp));
}
The body was always meant to run at most once (it only computes the next
optr from the updated tsto). The while was a latent bug because the
body never advances the loop variables.
Validated: isp.ko builds with RC=0 after applying the fix.
Fix validation
- Patch applies cleanly:
Hunk #1 succeeded at 5114. makeinsys/dev/disk/isp/βisp.ko+ all FC firmware modules linked,ISP_RC=0.- Cannot boot-test (no QLogic ISP FC adapter + no
ISP_TARGET_MODE);fix_status: not_testable.
PoC changes
harness.cwritten from scratch. Simulates queue pointers and proves the loop body never advanceststo(capped at 1M iters).
Fix verification
not_testablecompile validated
module build rc=0
Confirmed kernel references
β
Detail
Exploit chain
none
Evidence (decisive lines)
β
Verdict
Source+harness. isp_intr while(tsto!=oop) body never advances -> infinite loop. Doubly gated (ISP_TARGET_MODE+HW).
No comments yet.