ieee80211_beacon_update: first app-IE install does pointer arithmetic on NULL bo->bo_appie and memcpy's the IE to near-NULL kernel address (guaranteed panic)
Summary
ieee80211_beacon_construct() records bo->bo_appie/bo_appie_len only when iv_appie_beacon != NULL at construct time. If an app IE is installed later (SIOCS80211 IOC_APPIE subtype BEACON - the standard hostapd/WPS beacon-IE plumbing on a running AP), the APPIE block in ieee80211_beacon_update() executes 'bo->bo_appie += adjust' on NULL and add_appie() memcpy's ie_len bytes to address 0x0+ie_len - a guaranteed fatal supervisor write. VERIFIED on stock INVARIANTS guest (software net80211 radio KLD with real-driver beacon discipline + setappie): 'Fatal trap 12, fault VA = 0x40 (= NULL + 64-byte IE), supervisor write, Stopped at memcpy+0x1c' within 100ms of the ioctl, guest down; fix validated (first-app-IE case handled explicitly): trigger clean. Privileged local DoS (SYSCAP_NONET_WIFI); reachable via ordinary hostapd/WPS operation - any AP whose beacon predates its first beacon app IE (the common ordering) panics on the first TBTT after the daemon pushes the IE; WPS state changes make this remotely inducible in WPS-enabled deployments. No uid0 route (write confined to the unmapped zero page).
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-3282 Β· 14 files| File | Type | Description | Size | |
|---|---|---|---|---|
| README.md | β | 2.5 KB | β raw | |
| VERDICT.md | β | 3.7 KB | β raw | |
| verdict.json | β | 4.1 KB | view raw | |
| manifest.json | β | 912 B | view raw | |
| fw.c | β | 9.7 KB | view raw | |
| Makefile | β | 177 B | β download | |
| setappie.c | β | 1.6 KB | view raw | |
| build.sh | β | 87 B | view raw | |
| run.sh | β | 111 B | view raw | |
| build.log | β | 5.6 KB | view raw | |
| run.log | β | 1020 B | view raw | |
| panic.txt | β | 2.0 KB | view raw | |
| env.txt | β | 256 B | view raw | |
| fix.diff | β | 973 B | view raw |
DF-3282 β ieee80211_beacon_update: NULL bo->bo_appie pointer arithmetic writes app IE to near-NULL kernel address (panic)
File: sys/netproto/802_11/wlan/ieee80211_output.c (pass 2 audit)
What
ieee80211_beacon_construct() (line 3215-3219) records
bo->bo_appie/bo->bo_appie_len only when vap->iv_appie_beacon != NULL
at beacon-construction time. If a beacon application IE is installed
later (SIOCS80211 IEEE80211_IOC_APPIE with subtype BEACON β exactly what
hostapd does when WPS is enabled/disabled on a running AP, or when any
app IE blob is pushed after the AP came up), ieee80211_beacon_update()'s
APPIE block (lines 3591-3613) computes
int adjust = aielen - bo->bo_appie_len; /* 0 -> 64 */
bcopy(bo->bo_tim_trailer, bo->bo_tim_trailer+adjust, bo->bo_tim_trailer_len);
bo->bo_tim_trailer += adjust;
bo->bo_appie += adjust; /* NULL + 64 == 0x40 */
...
frm = add_appie(bo->bo_appie, aie); /* memcpy to 0x40 */
bo->bo_appie is NULL (never set), so the IE is memcpy'd to kernel
address 0x0+ie_len β a guaranteed fatal page fault on every
execution. Reproduced on the stock INVARIANTS guest:
fw: wlan0 RUN, beacon allocated <- beacon built with no app IE setting 64-byte beacon app IE on wlan0... (SIOCS80211 APPIE, root) Fatal trap 12: page fault while in kernel mode fault virtual address = 0x40 fault code = supervisor write data, page not present Stopped at memcpy+0x1c: movq %rdx,(%rdi)
Build / run (repo root)
sh findings/poc/DF-3282/build.sh # builds /root/fw/fw.ko + setappie in guest sh findings/poc/DF-3282/run.sh # baseline: panics within ~100ms of ioctl
The harness (fw.c) is a minimal software net80211 radio: registers an
ieee80211com ("fw0") with hostap support, allocates the beacon via
ieee80211_beacon_alloc() on RUN and services ieee80211_beacon_update()
from a 100 ms callout β the same discipline as a real MAC driver at TBTT.
Expected output
Baseline (stock kernel): panic/fatal trap 12, fault VA = ie_len (0x40),
guest down (see panic.txt).
Patched (fix.diff applied, kernel rebuilt): ioctl succeeds, beacon keeps
updating (dmesg shows continued beacon ticks, ifconfig wlan0 destroy
works, guest stays up). See VERDICT.md.
Threat
Privileged local DoS (SIOCS80211 requires SYSCAP_NONET_WIFI). Reachable through the standard hostapd/WPS beacon-IE plumbing on any running AP whose beacon predates the first app IE β the common ordering.
DF-3282 VERDICT β VERIFIED / reproduced / fixed
Bottom line
Reproduced: yes. Impact: panic (privileged local DoS). Status after fix: fixed.
ieee80211_beacon_update() writes a newly-installed beacon application IE
to kernel address 0x0+ie_len whenever the first app IE is installed on a
vap whose beacon was constructed without one. The root cause is pointer
arithmetic on a NULL bo->bo_appie:
sys/netproto/802_11/wlan/ieee80211_output.c:3215-3219βieee80211_beacon_construct()only recordsbo->bo_appiewhenvap->iv_appie_beacon != NULLat construct time (beacons are built once, at vap RUN).sys/netproto/802_11/wlan/ieee80211_output.c:3599-3612β on the first update after an app IE is installed (SIOCS80211 IEEE80211_IOC_APPIE, subtype BEACON β the standard hostapd/WPS beacon-IE plumbing), the code doesbo->bo_appie += adjustwithbo->bo_appie == NULLand thenadd_appie()memcpy'sie_lenbytes to that address.
How it was reproduced (stock INVARIENTS kernel, #0 Jul 2 06:02:54)
Harness: fw.c β a ~350-line software net80211 radio (KLD) that registers
ieee80211com "fw0", supports hostap, allocates the beacon with
ieee80211_beacon_alloc() on RUN and services
ieee80211_beacon_update() from a 100 ms callout (real-driver discipline).
No wifi hardware needed.
kldload fw.ko ifconfig wlan create wlandev fw0 wlanmode ap ifconfig wlan0 ssid fwtest mode 11b channel 1 up -> "fw: wlan0 RUN, beacon allocated" (beacon built, NO app IE) ./setappie wlan0 (SIOCS80211 APPIE, 64B vendor IE) -> <=100 ms later: Fatal trap 12: page fault while in kernel mode fault virtual address = 0x40 <-- NULL + 64 (exactly the IE length) fault code = supervisor write data, page not present Stopped at memcpy+0x1c: movq %rdx,(%rdi) <-- add_appie's memcpy
Full serial-console capture in panic.txt; command transcript in
run.log. Guest down after the fault (vm.sh status => down).
Exploit chain
None beyond denial of service: the write address is 0x0+N with
N = ie_len β€ 1024, always inside the unmapped zero page on x86-64. It is
a hard kernel panic (CWE-476/682 family), not a controllable-corruption
primitive.
Fix validation
fix.diff makes the update path handle the first-app-IE case explicitly:
the new IE occupies the space vacated at the head of the shifted trailer
and becomes part of the trailer (so later TIM resizes move it too).
- Baseline (stock kernel): panic within one beacon tick β see
panic.txt. - Patched (
patch -p1 < fix.diff+make nativekernel && make installkernel, kernel #1 Sep 10 04:41):setappiesucceeds, beacon keeps updating for 40+ ticks, guest stays up,ifconfig wlan0 destroy+kldunload fwcomplete cleanly.
fix_status: fixed, fix_baseline_reproduced: 1, fix_patched_reproduced:
0 (the bug no longer manifests).
Threat model notes
SIOCS80211 requires SYSCAP_NONET_WIFI (ieee80211_ioctl.c:3472) β root or
a capability-granted network-wifi manager (hostapd/wpa_supplicant run as
exactly this). The trigger ordering (beacon allocated before first app IE)
is the common case for an AP whose config daemon attaches WPS/interworking
IEs after the interface is already beaconing, and it is remotely inducible
in WPS deployments (the WPS state machine rewrites beacon IEs on
unauthenticated user interaction).
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
fixedPatched kernel rebuilt in-guest (make nativekernel + installkernel) with fix.diff applied: the exact baseline trigger sequence now completes without any fault (beacon ticks continue 40+, vap destroy + kldunload clean, guest up). Baseline on stock kernel panicked within one beacon tick.
Serial console before/after: panic.txt (baseline fault VA 0x40) vs run.log patched section + guest 'up' status after both triggers; kernel build log /root/kernelbuild2.log in guest.
Confirmed kernel references
Detail
Exploit chain
hostapd/WPS-style beacon app-IE install on a running AP whose beacon predates the first app IE (SIOCS80211 IEEE80211_IOC_APPIE subtype BEACON, SYSCAP_NONET_WIFI) -> next TBTT ieee80211_beacon_update() -> NULL+adjust pointer arithmetic -> memcpy to 0x40 -> page fault -> kernel panic (DoS). Write address is confined to the unmapped zero page, so no escalation beyond panic.
Evidence (decisive lines)
['panic.txt (Fatal trap 12, fault VA 0x40, supervisor write, memcpy+0x1c)', 'run.log (5-step transcript)', 'fw.c (software ieee80211com with beacon_alloc/beacon_update callout)', 'setappie.c (SIOCS80211 APPIE trigger)', 'build.log (untrimmed KLD build)']
PoC changes
Wrote the entire harness (no seed existed): fw.c fake-wifi KLD (net80211 radio with hostap + C_TXFRAG + beacon callout), setappie.c; fixed ioctl calling convention (SIOCS80211 takes ieee80211req directly, not ifreq.ifr_data), DFly ifconfig clone syntax (wlanmode ap), added driver nop callbacks the state machine calls.
Verified recommended fix
In ieee80211_beacon_update()'s APPIE block, handle bo_appie==NULL by placing the first app IE in the space vacated at the head of the shifted trailer (and fold it into bo_tim_trailer/len so TIM resizes track it) instead of doing pointer arithmetic on NULL.
Verdict
ieee80211_beacon_update() performs 'bo->bo_appie += adjust' on a NULL bo->bo_appie when the first beacon app IE is installed after the beacon was constructed, then add_appie() memcpy's the IE to kernel address 0x0+ie_len: guaranteed fatal page fault. Reproduced on the stock INVARIANTS guest with a software net80211 radio (fw.ko) + privileged SIOCS80211 APPIE ioctl: 'Fatal trap 12, fault virtual address = 0x40 (= NULL + 64-byte IE), supervisor write, Stopped at memcpy+0x1c', guest down within 100ms of the ioctl. fix.diff (first-app-IE lands in the vacated trailer head) validated by kernel rebuild: ioctl succeeds, beacon updates continue, vap destroy + kldunload clean, guest up.
No comments yet.