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

bwn_intr_noise missing re-entry guard: 9th noise-sample interrupt writes 4 bytes past noi_samples into mac_phy

Summary

BWN_INTR_NOISESAMPLE_OK stays unmasked in BWN_INTR_MASKTEMPLATE after the 8-sample noise window closes. A stale/duplicate noise interrupt re-enters bwn_intr_noise, which has no runtime guard (entry guards are KASSERTs only, compiled out of production): i=noi_nsamples=8 and noi_samples[8][0..3] writes 4 bytes past the [8][4] array - into struct bwn_phy mac_phy (single kmalloc'd bwn_mac) - corrupting phy type/rev/analog with RSSI-LUT bytes. INVARIANTS kernels panic at KASSERT instead. Firmware-interrupt anomaly (same duplicate-reporting class the driver documents for TX-done) or malicious card on a G-PHY bwn device; realistic outcome is panic on stock kernels, silent intra-object PHY-struct corruption otherwise. Source-certain; guest hardware-absent.

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-3594 Β· 7 files
FileTypeDescriptionSize
README.md β€” 938 B ↓ raw
VERDICT.md β€” 3.3 KB ↓ raw
probe.sh β€” 838 B view raw
run.log β€” 581 B view raw
fix.diff β€” 679 B view raw
manifest.json β€” 1.1 KB view raw
verdict.json β€” 2.2 KB view raw

DF-3594 β€” bwn_intr_noise re-entry after sample collection completes β†’ 4-byte OOB write past noi_samples into mac_phy (or KASSERT panic)

Build / Run / Expected

# on the DF guest, as root:
sh probe.sh

Guest result: driver resident, no Broadcom hardware β†’ runtime inconclusive. On a BCM43xx (G-PHY) machine whose firmware raises an extra BWN_INTR_NOISESAMPLE_OK after the 8-sample window closed (spurious/stale interrupt, or a malicious card), the expected observation:

  • INVARIANTS kernels: panic: kassert "/sys/dev/netif/bwn/bwn/if_bwn.c:5198: fail"
  • non-INVARIANTS kernels: silent 4-byte out-of-bounds write at mac->mac_noise.noi_samples[8][0..3] β€” past the [8][4] array into struct bwn_phy mac_phy (if_bwnvar.h:576-580, :917-918) β€” corrupting mac_phy.type/rev/analog with RSSI-LUT bytes influenced by the received signal, leading to subsequent misbehavior/panic in PHY dispatch.
VERDICT.md
↓ download raw

VERDICT β€” DF-3594

Status: inconclusive at runtime (no bwn hardware on the audit guest); defect source-certain. Impact: panic (INVARIANTS) / 4-byte intra-object OOB write into struct bwn_phy (non-INVARIANTS).

Root cause (path:line)

bwn_intr_noise() (sys/dev/netif/bwn/bwn/if_bwn.c:5181-5230) runs on every BWN_INTR_NOISESAMPLE_OK:

  1. The noise-sampling state machine: bwn_task_30s() (:6794-6804) sets noi_running = 1; noi_nsamples = 0 and requests a sample (bwn_noise_gensample :5409-5418).
  2. Each interrupt appends: i = mac->mac_noise.noi_nsamples; (:5200), mac->mac_noise.noi_samples[i][0..3] = … (:5205-5208), noi_nsamples++ (:5209). When the count reaches 8 the driver computes the average and terminates sampling: noi_running = 0; (:5225) β€” but the sample-interrupt is never masked off: BWN_INTR_NOISESAMPLE_OK is part of BWN_INTR_MASKTEMPLATE (sys/dev/netif/bwn/bwn/if_bwnreg.h:324-328, installed as mac_intr_mask at if_bwn.c:2137 and re-enabled at the end of every bwn_intrtask at :5023), and bwn_intrtask invokes bwn_intr_noise() whenever the bit is set (:4997-4998).
  3. There is no noi_running / noi_nsamples < 8 runtime guard at function entry (:5189-5200): only KASSERT(mac->mac_noise.noi_running) (:5192) and KASSERT(noi_nsamples < 8) (:5198-5199), which are compiled out of non-INVARIANTS kernels and are panics rather than guards on INVARIANTS ones.
  4. A ninth invocation (stale/spurious firmware interrupt β€” same duplicate-reporting behavior the driver documents for TX-done at :7088-7091, or a malicious card raising the bit) with noi_nsamples == 8 executes noi_samples[8][j] = (:5205-5208).

struct bwn_noise ends with int8_t noi_samples[8][4] (sys/dev/netif/bwn/bwn/if_bwnvar.h:576-580) and is immediately followed by struct bwn_phy mac_phy inside struct bwn_mac (if_bwnvar.h:917-918) β€” the mac object is a single kmalloc(sizeof(*mac)) (if_bwn.c:586). The write lands on mac_phy.type/rev/analog (if_bwnvar.h:442-445) with values pg_nrssi_lt[clamped rssi byte] β€” firmware-controlled, RF-influenced data. PHY type corruption feeds later dispatch (bwn_rate_init :2402, bwn_set_opmode, PHY op pointer selection at attach is already done β€” so this mostly yields wrong-code-path panics rather than a controlled hijack; honest impact: kernel-memory corruption with limited control, realistic outcome panic).

Why runtime reproduction was not possible

Same as DF-3593: virtio-only guest, no BCM43xx card (run.log). The G-PHY noise-sample interrupt cannot be raised. No uid0 chain β€” the write offset is fixed (+32 bytes into mac_phy) and the value domain is a 64-entry RSSI LUT.

Fix

Early-return unless the state machine expects a sample β€” see fix.diff.

Artifacts

  • probe.sh, run.log β€” guest probe (driver residency + hardware absence)
  • fix.diff β€” proposed patch vs read-only sys/ tree (never applied)

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 authored against read-only sys/; cannot baseline-validate without BCM43xx hardware

fix.diff in this pack
↓ fix.diffper-fix-DF-3594

Confirmed kernel references

Detail

Evidence (decisive lines)

VERDICT.md path:line trace incl. struct layout adjacency; run.log guest probe; fix.diff adds noi_running/nsamples entry guard

PoC changes

No runnable PoC possible without hardware; probe.sh substitutes

Verified recommended fix

Early-return in bwn_intr_noise unless noi_running && noi_nsamples < 8

Verdict

Source-certain missing guard in bwn_intr_noise (if_bwn.c:5189-5209): NOISESAMPLE_OK stays unmasked in BWN_INTR_MASKTEMPLATE (if_bwnreg.h:324-328) after the 8-sample window closes (noi_running=0 at if_bwn.c:5225), so a 9th/stale firmware noise interrupt indexes noi_samples[8] β€” a 4-byte OOB write into the adjacent struct bwn_phy within the kmalloc'd bwn_mac (if_bwnvar.h:576-580, 917-918). INVARIANTS kernels (stock DF) panic at KASSERT if_bwn.c:5198 instead. Guest has no Broadcom 802.11 device (run.log) so runtime trigger impossible; trigger class = duplicate/stale device interrupt, the same firmware behavior the driver documents for TX-done (if_bwn.c:7088-7091) or a malicious card.