iwm_notif_intr: 12-bit closed_rb_num compared against 256/512-entry ring positions - non-terminating interrupt-context loop, hard system hang (iwm twin of DF-3581)
Summary
hw = le16toh(sc->rxq.stat->closed_rb_num) & 0xfff yields 0..4095 from device-DMA'd shared memory, but the consumption loop advances ring->cur = (ring->cur+1) % count with count = 256/512. Any device-written closed_rb_num in [count,4096) makes the while (sc->rxq.cur != hw) predicate unsatisfiable: infinite loop in the interrupt handler holding sc->sc_lk with IWM_CSR_INT_MASK cleared - unattended whole-system hang with no panic or dump (even the watchdog cannot fire). Identical pattern to iwn DF-3581. Fix: mask to the ring size (count-1).
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-3633 Β· 6 files| File | Type | Description | Size | |
|---|---|---|---|---|
| README.md | β | 2.1 KB | β raw | |
| VERDICT.md | β | 2.1 KB | β raw | |
| env.txt | β | 740 B | view raw | |
| fix.diff | β | 343 B | view raw | |
| manifest.json | β | 775 B | view raw | |
| verdict.json | β | 2.1 KB | view raw |
DF-3633 β iwm_notif_intr: 12-bit closed_rb_num vs 256/512-entry ring β non-terminating interrupt-loop hang
Where
sys/dev/netif/iwm/if_iwm.c:5693-5737 (iwm_notif_intr), constants
if_iwmvar.h:287-288 (IWM_RX_LEGACY_RING_COUNT 256,
IWM_RX_MQ_RING_COUNT 512), struct iwm_rb_status.closed_rb_num
documentation "closed_rb_num [0:11]" (if_iwmreg.h, iwl-fh.h block).
What
hw = le16toh(sc->rxq.stat->closed_rb_num) & 0xfff; /* if_iwm.c:5710 */
while (sc->rxq.cur != hw) { /* :5715 */
data = &ring->data[ring->cur];
...
iwm_handle_rxb(sc, data->m);
ring->cur = (ring->cur + 1) % count; /* count = 256 / 512 */
}
sc->rxq.stat is device-DMA'd shared memory. ring->cur cycles through
[0, count), but hw is masked to 12 bits (0..4095). Any device-written
closed_rb_num in [count, 4096) (256..4095 legacy, 512..4095 mq) can
never equal ring->cur β the loop never terminates: the interrupt handler
spins forever reprocessing the ring, holding sc->sc_lk, with interrupts
masked β a hard system hang (no watchdog, no panic, no serial console
progress). This is the iwm twin of iwn's DF-3581 ("12-bit firmware
closed_count vs 64-slot ring"), where the ring-size mismatch class was
established.
Even when the loop does terminate, hw values β₯ count are never validated,
so (ring->cur + 1) % count vs raw hw bookkeeping stays inconsistent
(hw = (hw == 0) ? count - 1 : hw - 1; at :5735 then feeds a bogus write
pointer to the device).
Threat model
Requires an errant/malicious device or firmware writing an out-of-range
closed_rb_num (device DMA is untrusted input per this audit's policy;
also plausible on firmware hiccup). Impact: unattended hard hang (DoS) of
the whole system β no panic, no dump.
Reproduce
Kernel path needs iwm hardware (absent on guest β env.txt). Logic: pick hw=300, count=256: cur cycles 0..255 forever.
Fix
fix.diff β mask hw with (count - 1), matching the ring the driver
actually walks (values β₯ count are impossible on compliant hardware, so the
mask only changes behavior for the malicious/errant case).
DF-3633 VERDICT
Status: inconclusive (kernel path not exercisable β no iwm hardware on guest). Confidence in the defect: certain (source-level loop arithmetic).
Verified in source
hw = le16toh(sc->rxq.stat->closed_rb_num) & 0xfff;(sys/dev/netif/iwm/if_iwm.c:5710) β 12-bit mask, values 0..4095.struct iwm_rb_statusdocuments the field as "[0:11]" (sys/dev/netif/iwm/if_iwmreg.h, iwl-fh.h comment block) β the hardware register is 12 bits wide while the driver ring isIWM_RX_LEGACY_RING_COUNT == 256orIWM_RX_MQ_RING_COUNT == 512(sys/dev/netif/iwm/if_iwmvar.h:287-288).- The consumption loop
while (sc->rxq.cur != hw)(if_iwm.c:5715-5727) advancesring->cur = (ring->cur + 1) % countβ cur is confined to[0, count). For anyhwin[count, 4096)the loop predicate can never be satisfied β infinite loop inside the interrupt handler while holdingsc->sc_lk(iwm_intr:5754) withIWM_CSR_INT_MASKcleared (:5755). System-wide hard hang, no panic. - Loop termination therefore silently depends on the device never writing a value β₯ ring size β device DMA is untrusted input.
Precedent: DF-3581 (iwn iwn_notif_intr, 12-bit closed_count vs 64-slot
ring, Low/CWE-835) β identical pattern, iwm twin.
Why not reproduced on the guest
No iwm PCI device exists (env.txt): iwm_notif_intr is only reachable from
the device interrupt, which never fires.
Impact ceiling
Hard hang / denial of service of the entire machine (interrupt-context infinite loop under the driver lock). No memory corruption. Requires errant/malicious device DMA β Low severity, consistent with DF-3581.
Fix validation
fix.diff authored (mask hw to ring size). In-kernel validation impossible
(no device) β fix_status: not_testable.
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
not_testablefix.diff masks hw to (count-1); applies cleanly; no device to validate in-kernel
fix.diff verified with patch --dry-run against sys/dev/netif/iwm/if_iwm.c; no kernel-level validation possible (no iwm device)
Confirmed kernel references
Detail
Evidence (decisive lines)
VERDICT.md; README.md; env.txt; fix.diff (mask hw with count-1, applies clean)
PoC changes
n/a - source-level verification
Verified recommended fix
fix.diff masks hw to (count-1)
Verdict
iwm_notif_intr() masks the device-DMA'd closed_rb_num to 12 bits (hw = ... & 0xfff, if_iwm.c:5710) but walks a 256-entry (legacy) or 512-entry (mq) ring with ring->cur = (ring->cur+1) % count (:5715-5727). Any device-written value in [count,4096) makes the while-loop predicate unsatisfiable -> infinite loop in interrupt context holding sc->sc_lk with interrupts masked = hard system hang, no panic. iwm twin of iwn DF-3581. Not exercisable on the guest (no iwm device, env.txt); loop arithmetic is certain from source.
No comments yet.