β¬’ DragonFlyBSD Kernel Audit
← triage Β· dashboard
DF-3633

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)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-3633 Β· 6 files
FileTypeDescriptionSize
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).

VERDICT.md
↓ download raw

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

  1. 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_status documents 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 is IWM_RX_LEGACY_RING_COUNT == 256 or IWM_RX_MQ_RING_COUNT == 512 (sys/dev/netif/iwm/if_iwmvar.h:287-288).
  2. The consumption loop while (sc->rxq.cur != hw) (if_iwm.c:5715-5727) advances ring->cur = (ring->cur + 1) % count β€” cur is confined to [0, count). For any hw in [count, 4096) the loop predicate can never be satisfied β†’ infinite loop inside the interrupt handler while holding sc->sc_lk (iwm_intr :5754) with IWM_CSR_INT_MASK cleared (:5755). System-wide hard hang, no panic.
  3. 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_testable
baseline no→ patch + rebuild →patched clean

fix.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)
↓ fix.diffper-fix-DF-3633

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.