Missing payload-length validation in iwm_rx_time_event_notif firmware notification handler
- File:
sys/dev/netif/iwm/if_iwm_time_event.c - Lines: 207β217 (cast + deref without length check)
- Severity: Info
- CVSS 3.1:
CVSS:3.1/AV:A/AC:H/PR:N/UI:N/S:U:C:N/I:N/A:L - CWE: CWE-125 Out-of-bounds Read (defense-in-depth; trusted firmware source)
- Confidence: likely
- Status: new
Summary
iwm_rx_time_event_notif casts pkt->data to struct iwm_time_event_notif *
and dereferences unique_id/action/status (24-byte struct) without
first confirming iwm_rx_packet_payload_len(pkt) >= sizeof(*notif).
The two sibling state-writing callbacks (iwm_te_notif:226-231,
iwm_time_event_response:257-262) and the neighboring
DTS_MEASUREMENT_NOTIFICATION handler (if_iwm.c:5535-5539) all perform
exactly this check; this direct RX-dispatch handler is the lone inconsistent
outlier.
Impact is limited because:
- the notification is trusted-firmware-generated (a remote 802.11 peer
cannot directly craft
TIME_EVENT_NOTIFICATIONpayloads), - the read values feed only control-flow branches and debug
printf(never copied to userspace, so no info leak), - the coalesced-RX mbuf is oversized so a short read stays within mapped memory (no page-fault panic in practice).
Root cause
At if_iwm_time_event.c:207-217:
struct iwm_time_event_notif *notif = (void *)pkt->data;
Then immediately reads le32toh(notif->unique_id) and le32toh(notif->action)
for IWM_DPRINTF (lines 212-214) and hands notif to iwm_te_handle_notif,
which reads notif->action (offset 16) and notif->status (offset 20,
line 176/242).
struct iwm_time_event_notif is 24 bytes (if_iwmreg.h:2939-2946).
The RX dispatch loop in if_iwm.c (HAVEROOM macro, line 5377-5378) only
guarantees room for sizeof(uint32_t)+sizeof(struct iwm_cmd_header) β i.e.
just the packet header, NOT 24 bytes of payload.
If the firmware emits a TIME_EVENT_NOTIFICATION whose len_n_flags
(if_iwmreg.h:6923) reports a payload shorter than 24 bytes, these reads
reference bytes past the valid payload (still inside the oversized RX buffer,
hence no fault).
Contrast iwm_te_notif (line 224-231) which computes
resp_len = iwm_rx_packet_payload_len(pkt) and rejects on mismatch, and
iwm_time_event_response (line 255-262) which does the same.
Threat model
Attacker position: the notification is produced by the WiFi card's
baseband firmware and DMA'd into host memory; a remote 802.11 attacker does
not have direct control over TIME_EVENT_NOTIFICATION field layout (that
path is firmware code, not frame parsing).
Realistic threat actors:
- (a) firmware bugs that have historically produced short/odd notifications in the iwlwifi family,
- (b) a malicious/compromised external WiFi adapter (e.g. a Thunderbolt/USB Wi-Fi dongle with hostile firmware) attacking the host kernel via DMA'd notifications.
Worst realistic impact: a logic glitch (a garbage action byte clearing
sc_time_event_duration via iwm_te_clear_data at line 194 if the
IWM_TE_V2_NOTIF_HOST_EVENT_END bit happens to be set) β a local
session-protection teardown DoS, not memory corruption or info leak.
No path to code execution or privilege escalation was found.
Proof of concept
No working kernel exploit is possible from this alone β there is no memory-corruption primitive (reads are in-buffer, non-faulting) and no info leak (values never reach userspace).
The defensive value of a PoC would be a regression-style fault-injection test:
- Build a kernel with
IWM_DEBUGand a DragonFlyBSD/iwm(4) guest with a 7260/8260-class NIC (or a patched firmware shim). - Force the firmware to emit a
TIME_EVENT_NOTIFICATIONwithlen_n_flagsreporting e.g. 8 bytes of payload. - Observe that
iwm_rx_time_event_notifstill dereferencesnotif->action(offset 16) andnotif->status(offset 20) past the valid 8 bytes without the guard its siblings enforce.
Because this is not user-exploitable, the evidence pack should be a regression-style fault-injection test rather than a privilege-escalation PoC.
Recommended fix
Mirror the guard used by iwm_te_notif:226-231 and the DTS handler at
if_iwm.c:5535. Reject short payloads before the cast.
--- a/sys/dev/netif/iwm/if_iwm_time_event.c
+++ b/sys/dev/netif/iwm/if_iwm_time_event.c
@@ -204,6 +204,13 @@ static void
void
iwm_rx_time_event_notif(struct iwm_softc *sc, struct iwm_rx_packet *pkt)
{
+ if (iwm_rx_packet_payload_len(pkt) < sizeof(struct iwm_time_event_notif)) {
+ device_printf(sc->sc_dev,
+ "time event: truncated notification (payload %u < %zu)\n",
+ iwm_rx_packet_payload_len(pkt),
+ sizeof(struct iwm_time_event_notif));
+ return;
+ }
struct iwm_time_event_notif *notif = (void *)pkt->data;
IWM_DPRINTF(sc, IWM_DEBUG_TE,
References
sys/dev/netif/iwm/if_iwm_time_event.c:207-217β the unguarded cast + derefsys/dev/netif/iwm/if_iwm_time_event.c:226-231β sibling handler with correct guardsys/dev/netif/iwm/if_iwm_time_event.c:257-262β sibling handler with correct guardsys/dev/netif/iwm/if_iwm.c:5535-5539β neighbor DTS handler with correct guardsys/dev/netif/iwm/if_iwmreg.h:6923,6947,2939-2946β RX packet layout + notif struct
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-1994 Β· 3 files| File | Type | Description | Size | |
|---|---|---|---|---|
| VERDICT.md | verdict | source-only confirmation + mechanism + fix | 1.6 KB | β raw |
| fix.diff | suggested-fix | Add resp_len = iwm_rx_packet_payload_len(pkt); if (resp_len < sizeof(*notif)) re | 873 B | view raw |
| ../fix_build_new.log | build-log | Batch kernel build with new fixes (rc=0, -Werror) | 5.6 MB | β download |
DF-1994 β PoC Verification Verdict
Category: net (module / HW-gated)
Source: sys/dev/netif/iwm/if_iwm_time_event.c:207-217
Guest: DragonFly dfbsd 6.5-DEVELOPMENT DragonFly 6.5-DEVELOPMENT #0: Thu Jul 2 06:02:54 UTC 2026 root@dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC x86_64 (X86_64_GENERIC, INVARIANTS ON, no SMAP/SMEP/KASLR)
Date verified: 2026-07-25
Verdict: REPRODUCED (source-only confirmation; HW/module-gated)
Mechanism
iwm_rx_time_event_notif(pkt): notif = (void*)pkt->data; derefs notif->unique_id/action without checking the rx packet payload length >= sizeof(struct iwm_time_event_notif). Malformed firmware notification (or attacker-controlled malicious NIC) can OOB-read.
In GENERIC kernel build: NO (module / not compiled into X86_64_GENERIC on audit QEMU guest)
Reproduction status
This finding is hardware/module gated: the vulnerable code path requires specific hardware (AMD GPU / radeon / Atheros NIC / RAID controller) or a loadable module not present on the audit QEMU guest. The QEMU guest has no GPU passthrough, no physical NIC/RAID HW, and these modules are not exercised. The bug is therefore confirmed by source-level trace of the cited path:line data flow rather than by a runtime PoC. The cited code, guards (or lack thereof), and types were verified against the audited sys/ tree.
Fix
Add resp_len = iwm_rx_packet_payload_len(pkt); if (resp_len < sizeof(*notif)) return;
See fix.diff for the standalone git-apply-able unified diff. Validated by applying the 38 new-finding batch diffs (including this one) and building a single X86_64_GENERIC kernel (rc=0, -Werror clean).
Fix verification
fixedVALIDATED: fix.diff applies cleanly + batch kernel build rc=0 -Werror; bug HW/module/runtime-gated, no runtime PoC re-test possible on guest.
VALIDATED: fix.diff applies cleanly + batch kernel build rc=0 -Werror; bug HW/module/runtime-gated, no runtime PoC re-test possible on guest.
Confirmed kernel references
β
Detail
Exploit chain
none
Evidence (decisive lines)
REPRODUCED (source-only): iwm_rx_time_event_notif derefs notif->unique_id/action without checking rx packet payload length >= sizeof(struct iwm_time_event_notif); malformed firmware notification -> OO
Verified recommended fix
REPRODUCED (source-only): iwm_rx_time_event_notif derefs notif->unique_id/action without checking rx packet payload length >= sizeof(struct iwm_time_event_notif); malformed firmware notification -> OOB read.
Verdict
REPRODUCED (source-only): iwm_rx_time_event_notif derefs notif->unique_id/action without checking rx packet payload length >= sizeof(struct iwm_time_event_notif); malformed firmware notification -> OOB read.
No comments yet.