Re-queued NOP-IN PDU in _nop_in causes bcopy(NULL) panic in isc_sendPDU
Summary
When target sends NOP-In with itt=0xFFFFFFFF and ttt!=0xFFFFFFFF _nop_in() mutates received PDU into NOP-OUT and re-queues via isc_qout(). Received PDUs have pp->ahs==NULL (so_recv sets pp->ahs_len from BHS AHSLength AHS bytes in pq->mp never in pp->ahs). If target sets AHSLength!=0 in NOP-In pp->ahs_len nonzero while pp->ahs NULL and when proc_out() runs re-queued PDU through isc_sendPDU() bcopy(pp->ahs ...) bcopy from NULL panics kernel. Remote DoS on default config. Attacker: iSCSI target post-Login full-feature phase. NOP-In/T logic normal iSCSI keep-alive so target can send without suspicion.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-2459 Β· 9 files| File | Type | Description | Size | |
|---|---|---|---|---|
| mtarget.c | trigger-source | malicious target: NOP-IN itt=ffffffff ttt=1 AHSLength=1 | 3.6 KB | view raw |
| idrv.c | trigger-source | minimal initiator driver (ISCSISETSOC pre-login) | 2.8 KB | view raw |
| build.sh | build-script | cc -o mtarget mtarget.c; cc -o idrv idrv.c | 65 B | view raw |
| run.sh | run-script | launch mtarget nopin + idrv | 89 B | view raw |
| panic.txt | panic-signature | Fatal trap 12 va=0x0 memmove+0xb5 | 642 B | view raw |
| env.txt | environment | uname, kern.version, cc, module sha256 | 482 B | view raw |
| fix.diff | suggested-fix | in _nop_in re-queue: clear stale ahs/ds lens, force i_prepPDU | 1.1 KB | view raw |
| VERDICT.md | verdict | full analysis | 4.1 KB | β raw |
| manifest.json | manifest | this catalog | 1.9 KB | view raw |
DF-2459 β Re-queued NOP-IN PDU in _nop_in causes bcopy(NULL) in isc_sendPDU
Verdict
REPRODUCED β remote kernel panic (DoS) from a malicious iSCSI target. The bug
is a NULL-pointer read (page fault @0x0) inside bcopy/memmove, not a
write primitive; no escalation chain applies (Phase 6 read-only hard blocker).
Fix validated on a rebuilt module.
Mechanism (trigger β primitive β effect)
- Same precondition as DF-2460: a privileged user passes a connected iSCSI
socket to the kernel via
ISCSISETSOC, starting the receiver thread before login (iscsi.c:430). - The malicious target sends a NOP-IN PDU (
opcode=0x20) withitt = 0xffffffffandttt != 0xffffffff, and a non-zeroAHSLength(e.g.AHSLength=1β 4 bytes of AHS). so_recv()(isc_soc.c:387-389) setspp->ahs_len = bhs->AHSLength*4and reads the AHS bytes into the mbuf chainpq->mpβ it never setspp->ahs, which staysNULL(frompdu_alloc'smemset)._nop_in()(isc_sm.c:195) takes theitt==-1 && ttt!=-1branch, mutates the BHS into a NOP-OUT (isc_sm.c:217-227) and re-queues the same PDU viaisc_qout()(isc_sm.c:228). Becausepq->lenis non-zero (set byso_recv),isc_qoutdoes not calli_prepPDU(isc_sm.c:309), so the stalepp->ahs_lensurvives.proc_out()dequeues the NOP-OUT and callsisc_sendPDU()(isc_sm.c:530), whose active (mbuf) implementation does:c if(pp->ahs_len) { /* isc_soc.c:120 -- true */ bcopy(pp->ahs, ..., pp->ahs_len); /* isc_soc.c:125 -- pp->ahs == NULL */bcopy(NULL, ...)faults reading address0x0.
Evidence (panic signature, unpatched #0 kernel)
Fatal trap 12: page fault while in kernel mode fault virtual address = 0x0 fault code = supervisor read data, page not present instruction pointer = 0x8:0xffffffff80bca9b5 ... Stopped at memmove+0xb5: movl (%rsi),%edx db>
memmove (called by bcopy) with %rsi==0 is the bcopy(pp->ahs==NULL,...).
Reproduced by mtarget nopin + idrv.
Threat model / privilege boundary
Identical to DF-2460: the attacker is the iSCSI target; the bug fires pre-login,
no auth needed; the privileged ISCSISETSOC (root, /dev/iscsi is 0600
root:wheel) is the only thing the victim must do (normal iscontrol usage).
Why no escalation (Phase 6 hard blocker)
NULL-pointer read (bcopy from NULL). No attacker-controlled write
destination, no content control, no object reuse β the read-only / no-write
hard blocker applies; the only effect is a kernel panic (DoS).
PoC changes
mtarget.c,idrv.c: same harness as DF-2460;nopinmode sends the 52-byte NOP-IN (opcode=0x20, F=1, AHSLength=1, itt=0xffffffff, ttt=1+ 4 AHS bytes).fix.diff(new): in_nop_in's re-queue branch, clear the stale AHS/data length fields (pp->ahs_len=0,pp->ds_len=0, pointers NULL) and forcei_prepPDUto re-prepare the outgoing NOP-OUT (pq->len=0).
Fix (fix.diff)
Root cause: a received PDU is re-queued for sending with pp->ahs_len set from
the wire but pp->ahs == NULL (AHS lives in pq->mp). The outgoing NOP-OUT
keep-alive carries no AHS/data, so the fix drops the stale length fields and
lets isc_qoutβi_prepPDU recompute pq->len/BHS lengths for the NOP-OUT.
Supersedes the finding markdown's proposal (which identified the
bcopy(pp->ahs) line; this fixes the root cause at the re-queue site).
Fix validation (rebuilt single module)
- Baseline (unpatched
#0): PoC panics βFatal trap 12 va=0x0 Stopped at memmove+0xb5(panic.txt). - Patched module (sha256
f71cd799...): PoC runs clean βidrvreports "still alive after 6s (no panic)", guest up, no panic in serial log.
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
fixedVALIDATED: mtarget(nopin)+idrv PANICS on unpatched #0 module ('Fatal trap 12 va=0x0 Stopped at memmove+0xb5') and does NOT panic on single-fix module (idrv reports 'still alive after 6s (no panic)', guest up).
baseline: Fatal trap 12 va=0x0 supervisor read data, Stopped at memmove+0xb5 (bcopy NULL). patched: 'idrv: still alive after 6s (no panic)' -- no panic, guest up.
Confirmed kernel references
Detail
Exploit chain
none (NULL-pointer READ -- bcopy from NULL). Read-only NULL-deref, not write primitive, no escalation chain derivable (Phase 6 read-only hard blocker). Realistic impact ceiling: remote kernel panic / DoS from malicious iSCSI target.
Evidence (decisive lines)
Fatal trap 12: page fault while in kernel mode | fault virtual address = 0x0 | fault code = supervisor read data, page not present | Stopped at memmove+0xb5: movl (%rsi),%edx [bcopy(pp->ahs==NULL,...) in isc_sendPDU]
PoC changes
Wrote mtarget.c (nopin mode: 52-byte NOP-IN itt=0xffffffff ttt=1 AHSLength=1 + 4 AHS bytes) and idrv.c (minimal initiator: open /dev/iscsi, ISCSISETSES, socket+connect, ISCSISETSOC -- starts kernel receiver PRE-login so injected NOP-IN processed). Plus fix.diff (clear stale ahs_len/ds_len in _nop_in re-queue).
Verified recommended fix
In _nop_in's re-queue branch (isc_sm.c:225-228), zero pp->ahs_len/pp->ahs/pp->ds_len/pp->ds and set pq->len=0 so isc_qout re-runs i_prepPDU for outgoing NOP-OUT keep-alive, preventing isc_sendPDU's bcopy(pp->ahs==NULL,...). Supersedes finding proposal (fixes root cause at re-queue site). Full git-apply-able diff in findings/poc/DF-2459/fix.diff.
Verdict
REPRODUCED. _nop_in (isc_sm.c:212-228) re-queues a received NOP-IN (itt=0xffffffff, ttt!=0xffffffff) as a NOP_OUT via isc_qout WITHOUT clearing pp->ahs_len, which so_recv set from wire AHSLength while pp->ahs stays NULL (received PDUs carry AHS in pq->mp, never pp->ahs). isc_sendPDU (isc_soc.c:120-125, mbuf build) then does bcopy(pp->ahs==NULL, ..., pp->ahs_len) -> page fault at 0x0. Confirmed by 'Stopped at memmove+0xb5: movl (%rsi),%edx' with fault virtual address 0x0 (NULL read in bcopy/memmove).
No comments yet.