NVM sections parsed at fixed word offsets against firmware-returned lengths (exact-size kmallocs) - heap OOB reads incl. regulatory[0x507] LAR read requiring >=2576 bytes
Summary
iwm_nvm_init() allocates each NVM section at the exact firmware-returned length, but iwm_parse_nvm_sections() only NULL-checks the pointers and iwm_parse_nvm_data() reads fixed offsets without consulting lengths: regulatory[0x507] reads bytes 0xA0E..0xA0F; 7000 channel flags memcpy reads SW bytes [64,142); 8000 flags read REGULATORY bytes [0,102); SKU/radio/n_hw_addrs/version; MAC override and HW addr nvm_hw[0x15]. Short sections -> OOB reads past small kmallocs into sc->nvm_data and a console-printed MAC. Firmware-controlled NVM content (same boundary as DF-1898/DF-2056): kernel heap OOB reads up to ~2.5KB past exact-size allocations, crash potential at page-adjacent boundaries. Fix: family-aware minimum section length validation.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-3632 Β· 6 files| File | Type | Description | Size | |
|---|---|---|---|---|
| README.md | β | 2.3 KB | β raw | |
| VERDICT.md | β | 2.3 KB | β raw | |
| env.txt | β | 740 B | view raw | |
| fix.diff | β | 1.7 KB | view raw | |
| manifest.json | β | 902 B | view raw | |
| verdict.json | β | 2.5 KB | view raw |
DF-3632 β NVM sections parsed with fixed offsets against firmware-returned lengths (heap OOB reads)
Where
sys/dev/netif/iwm/if_iwm.c:2215-2276 (iwm_parse_nvm_data and its helpers
iwm_get_sku/iwm_get_nvm_version/iwm_get_radio_cfg/iwm_get_n_hw_addrs
:2120-2161, iwm_set_hw_address :2184-2213,
iwm_set_hw_address_family_8000 :2061-2118), fed by iwm_nvm_init()
:2339-2393.
What
Each NVM section is read from the firmware into an exact-size heap allocation:
temp = kmalloc(len, M_DEVBUF, M_WAITOK); /* len == bytes the FW returned */
memcpy(temp, nvm_buffer, len);
nvm_sections[section].data = temp; /* if_iwm.c:2367-2375 */
iwm_parse_nvm_sections() only checks that section pointers are non-NULL
(:2290-2333) β the section lengths are never validated β and then
iwm_parse_nvm_data() reads fixed word offsets from them:
iwm_get_sku():nvm_sw[IWM_SKU=2],phy_sku[IWM_SKU_8000=2](:2125-2127)iwm_get_n_hw_addrs():nvm_sw[3](:2156-2158)- family 7000 channel flags:
memcpy(..., &nvm_sw[IWM_NVM_CHANNELS], IWM_NUM_CHANNELS*2)whereIWM_NVM_CHANNELS = 0x1E0-0x1C0 = 32(u16 index) β reads SW bytes[64, 142)(:2266-2269) - family 8000 channel flags:
memcpy(..., ®ulatory[IWM_NVM_CHANNELS_8000=0], 51*2)β REGULATORY bytes[0, 102)(:2270-2273) - LAR config:
regulatory[IWM_NVM_LAR_OFFSET_8000=0x507]β REGULATORY bytes[0xA0E, 0xA10)= offset 2574 (:2251-2255) β the section must be β₯ 2576 bytes, never checked - MAC override:
mac_override[1..4](:2072-2073), HW addr:nvm_hw[IWM_HW_ADDR=0x15]β HW bytes[0x2A, 0x30)(:2194)
A firmware that returns a short section (e.g. an 8-byte SW section) makes
each of these a heap OOB read past a small kmalloc allocation. The read
values populate sc->nvm_data (channel map, radio cfg, MAC address) and the
MAC is printed to the console (if_iwm.c:6386-6389).
Threat model
Firmware-controlled NVM content (same trust boundary as DF-1145/DF-1898; DF-1898 rated Low, DF-2056 rated Medium for the paging variant). No guest iwm hardware β source-level certainty (env.txt).
Fix
fix.diff β validate minimum section lengths in iwm_parse_nvm_sections()
before parsing (family-aware requirements, incl. the 0x507/0x4C7 LAR
offsets).
DF-3632 VERDICT
Status: inconclusive (kernel path not exercisable β no iwm hardware on guest). Confidence in the defect: certain (source-level).
Verified in source
- Section buffers are exact-size heap allocations of the firmware-returned
length:
temp = kmalloc(len, ...)atsys/dev/netif/iwm/if_iwm.c:2367withlenfromiwm_nvm_read_section()(bytes the firmware actually returned,:1950-1955). - The only "validation" before parsing is non-NULL pointer checks
(
if_iwm.c:2290-2333).struct iwm_nvm_section.length(if_iwm.c:247-250) is recorded and then never consulted again. - The parse performs fixed-offset reads listed in README.md; the largest is
le16_to_cpup(regulatory + 0x507)(if_iwm.c:2251-2255), which reads bytes 0xA0E..0xA0F of the REGULATORY section; the channel-flag memcpys read 78/102 bytes at fixed offsets (:2266-2273); MAC/SKU/radio reads touch fixed words (:2072-2073, 2125-2158, 2194). With a short section each is a heap OOB read past a small kmalloc. - Data sink:
sc->nvm_datafields β channel map (iwm_init_channel_map:2028-2059), MAC printed viaether_sprintf()at:6386-6389.
Precedent: DF-1898 (phy_db FW lengths unvalidated, Low) and DF-2056 (paging FW sections unvalidated, Medium) β same driver, same trust boundary; this is the NVM-sections instance living in if_iwm.c, missed in pass 1.
Why not reproduced on the guest
No iwm PCI device; iwm_nvm_init() runs only from the firmware-bring-up path
(iwm_run_init_ucode(sc, 1) β iwm_preinit), which requires the device.
Impact ceiling
Kernel heap OOB reads (tens of bytes to ~2.5KB past exact-size kmallocs) of attacker(untrusted-FW)-influenced content into driver state and console/log output (MAC string). Crash potential when adjacent allocations end at page boundaries. Severity: Low (privileged/physical trust boundary), consistent with DF-1898.
Fix validation
fix.diff authored; 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 validates family-aware minimum section lengths in iwm_parse_nvm_sections(); 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 (per-offset byte requirements); env.txt; fix.diff (minimum section-length validation, applies clean)
PoC changes
n/a - source-level verification
Verified recommended fix
fix.diff validates family-aware minimum section lengths in iwm_parse_nvm_sections()
Verdict
NVM sections are kmalloc'd at the exact firmware-returned length (if_iwm.c:2367-2375) but iwm_parse_nvm_data() and helpers read fixed word offsets without ever consulting nvm_sections[].length: e.g. regulatory[0x507] LAR read needs >=2576 bytes (:2251-2255), 7000 channel flags read SW bytes [64,142) (:2266-2269), 8000 flags read REGULATORY bytes [0,102) (:2270-2273), SKU/radio/n_hw_addr/MAC reads at fixed indices (:2072,:2125-2158,:2194). A short section yields heap OOB reads past small exact-size allocations; parsed data feeds the channel map and a console-printed MAC (:6386-6389). Same trust boundary as DF-1898 (Low). No iwm device on guest -> not exercisable (env.txt); source-level certainty.
No comments yet.