Cipher registry has no reference accounting: ieee80211_crypto_unregister clears ciphers[] while keys may still hold wk_cipher into the module; policy-module nrefs gate read unsynchronized at MOD_UNLOAD ('XXX disallow if references') - kldunload TOCTOU -> UAF
Summary
ieee80211_crypto_unregister NULLs ciphers[cip] with the code's own admission 'XXX disallow if references'; the policy-module unload gate checks the cipher module's nrefs without synchronization against the nrefs++ the cipher performs in ic_attach under the key-update lock. kldunload wlan_ccmp racing a CCMP key install unlinks the module while key->wk_cipher still points into it; every later ic_encap/ic_decap/ic_detach through that key calls unmapped text. Root-gated both sides, narrow window - hardening-grade (Info). Not runnable on this guest (no radio). DF-0640 still unfixed (noted). Fix: per-cipher reference counter checked under the wlan serialization at unregister/unload.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-3438 Β· 3 files| File | Type | Description | Size | |
|---|---|---|---|---|
| README.md | β | 1.9 KB | β raw | |
| verdict.json | β | 1.9 KB | view raw | |
| manifest.json | β | 575 B | view raw |
DF-3438 β wlan cipher registry has no reference accounting: module unload TOCTOU vs key attach (XXX disallow if references)
sys/netproto/802_11/wlan/ieee80211_crypto.c:
ieee80211_crypto_unregister(:213-228) clearsciphers[cip]with the in-code admission/* XXX disallow if references */β it does not know how many keys still holdkey->wk_cipher == cip.- The policy-module glue
_IEEE80211_POLICY_MODULE(ieee80211_dragonfly.h:250-262) gates MOD_UNLOAD on the module's ownnrefs, but that read is not synchronized with thenrefs++the cipher does inic_attachunder the key-update lock (e.g.ieee80211_crypto_ccmp.c:115):kldunload wlan_ccmpcan pass thenrefs == 0check concurrently with a vap installing a CCMP key; the module then unlinks whilekey->wk_cipherpoints into its text/data β every subsequentic_encap/ic_decap/ic_detachcall through that key is a call into unmapped memory (UAF).
Also on the same theme: ieee80211_crypto_register (:194-207) will not
replace an existing entry, and ciphers[] is written without exclusion
against a concurrent ieee80211_crypto_available/newkey reader β benign
pointer-slot races on aligned words, but the unregister side is the
dangerous one.
Hardening-grade: trigger requires root (kldunload wlan_ccmp) racing a
root-driven key install (wpa_supplicant/ifconfig wpa), both sides
privileged; impact is kernel UAF (panic β potentially worse). The fix is
the one the code already asks for: count references per cipher
(nrefs-style) in ieee80211_crypto_register/unregister under the
existing wlan serialization and refuse unload while keys are bound
(clearing ciphers[] only when the count drops to zero).
Verification status
untested β no radio hardware on the guest (vap/key installation against a real cipher needs an 802.11 parent). Code walk is the evidence.
Fix verification
not_testableConfirmed kernel references
Detail
Evidence (decisive lines)
['README.md: path:line walk (unregister vs attach/nrefs)']
Verified recommended fix
Add reference counting to the cipher registry so unregister/unload is refused while keys are bound to the cipher.
Verdict
Info/hardening, not exercised (guest has no 802.11 radio, so cipher keys cannot be installed against a real cipher module). Code walk: ieee80211_crypto_unregister (ieee80211_crypto.c:213-228) clears ciphers[cip] with the in-code admission 'XXX disallow if references' - no reference accounting exists; the policy-module unload gate (_IEEE80211_POLICY_MODULE, ieee80211_dragonfly.h:250-262) checks the cipher module's nrefs unsynchronized against the nrefs++ the cipher performs in ic_attach under the key-update lock (ieee80211_crypto_ccmp.c:115). kldunload wlan_ccmp racing a CCMP key install can unlink the module while key->wk_cipher still points into it; subsequent ic_encap/ic_decap/ic_detach calls through that key jump into unmapped module text (UAF). Both trigger sides are root-gated; the window is narrow; severity Info for triage but the consequence is a kernel UAF.
No comments yet.