TOCTOU in MACCMD_LIST: as_nacls read without lock before buffer sizing β heap OOB write (grow) and uninit heap info leak (shrink)
Summary
ieee80211_acl.c:313 space=as->as_nacls*IEEE80211_ADDR_LEN read WITHOUT ACL_LOCK (not taken until :328). :319 kmalloc(space,M_TEMP,M_INTWAIT) NO M_ZERO. :328 ACL_LOCK. :329-331 TAILQ_FOREACH writes ap[i++] for every entry under lock. Grow race: concurrent ADDMAC between :313 and :328 widens list foreach writes past ap end = heap OOB write of attacker-controlled MAC bytes. Shrink race: concurrent DELMAC/FLUSH shrinks list ap tail uninitialized copyout ships uninit heap to userland = info leak. Local-root trigger: two threads SIOCS80211 ADDMAC + SIOCG80211 MACCMD_LIST same vap. Attacker-controlled content (MAC addresses) + slab grooming = arbitrary kernel write primitive. Fix: take ACL_LOCK before reading as_nacls add M_ZERO bound foreach to space/ADDR_LEN.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-0732 Β· 21 files| File | Type | Description | Size | |
|---|---|---|---|---|
| VERDICT.md | verdict | full narrative: line-by-line TOCTOU, harness methodology, grow+shrink evidence, fix before/after | 10.5 KB | β raw |
| README.md | readme | summary + reproduce instructions | 2.5 KB | β raw |
| harness.c | trigger-source | deterministic userspace transcription of acl_getioctl MACCMD_LIST (PRIMARY proof; BUGGY + -DFIXED builds) | 12.5 KB | view raw |
| harness_mod.c | exploit-chain | real-kernel object-level harness module exercising actual acl_getioctl via fake vap + /dev/df0732 | 7.9 KB | view raw |
| Makefile | trigger-source | build for harness_mod.ko (bsd.kmod.mk) | 452 B | β download |
| trigger.c | trigger-source | userspace racer: drives LIST ioctl, detects grow panic + shrink leak | 4.6 KB | view raw |
| leakcheck.c | trigger-source | definitive WEIRD_ADDR residue classifier (distinguishes real heap leak from valid MACs) | 3.7 KB | view raw |
| build.sh | build-script | builds BUGGY + FIXED harness transcriptions | 517 B | view raw |
| run.sh | run-script | runs all 4 scenarios (buggy/fixed x grow/shrink) | 1.5 KB | view raw |
| fix.diff | suggested-fix | git-apply-able: ACL_LOCK before as_nacls read + M_ZERO + bounded foreach | 1.6 KB | view raw |
| build.log | build-log | harness build output (BUGGY + FIXED, -Wall clean) | 275 B | view raw |
| run.log | run-log | deterministic harness run: BUGGY both CONFIRMED, FIXED both NOT TRIGGERED | 2.3 KB | view raw |
| trigger_run.log | run-log | real-kernel buggy trigger: 7 shrink-leak hits then guest panicked | 665 B | view raw |
| fix_trigger_run.log | run-log | real-kernel FIXED trigger: 241489 ioctls, no panic, guest UP | 861 B | view raw |
| fix_run.log | run-log | FIXED harness run + real-kernel leakcheck: WEIRD_ADDR residue=0 | 2.9 KB | view raw |
| fix_build.log | build-log | wlan_acl.ko fixed build (-Werror clean) | 1.3 KB | view raw |
| panic.txt | panic-signature | real-kernel grow-race panic: acl_getioctl+0xd6 movw %si,0x4(%rcx) | 715 B | view raw |
| leak_sample.txt | leak-sample | real-kernel shrink-race leak: kernel string residue '..Copy' + varying bytes | 1.0 KB | view raw |
| env.txt | environment | uname, cc version, module/ifconfig state | 554 B | view raw |
| ../fix_build_combined.log | build-log | Combined 41-finding kernel build (rc=0, -Werror clean) | 5.6 MB | β download |
| ../fix_build_summary.txt | build-summary | Summary of the combined 41-finding kernel build | 826 B | view raw |
DF-0732 β TOCTOU in wlan_acl acl_getioctl MACCMD_LIST
Verdict: REPRODUCED (heap OOB write + uninit-heap info leak); fix VALIDATED. Severity: High. CWE: CWE-787 (OOB write), CWE-908 (uninit memory).
The bug
sys/netproto/802_11/wlan_acl/ieee80211_acl.c:313 reads as->as_nacls WITHOUT
ACL_LOCK (taken only at :328) to size the kmalloc(space, M_TEMP, M_INTWAIT)
at :319 (no M_ZERO), then TAILQ_FOREACH (:329-332) writes every current
list entry unbounded. A concurrent ADDMAC/DELMAC between :313 and :328 makes
the list diverge from the buffer size:
- Grow β OOB heap write of attacker-controlled MAC bytes past the buffer.
- Shrink β uninitialized tail shipped to userland by copyout (info leak).
Reproduce (userspace deterministic harness β PRIMARY proof)
sh build.sh # builds harness (BUGGY) + harness_fixed (FIXED) sh run.sh # BUGGY => both races CONFIRMED; FIXED => both NOT TRIGGERED
Reproduce (real-kernel object-level harness β needs root to kldload)
# build harness_mod.ko (in guest, as root): cd /root/df0732 && make SYSDIR=/usr/src/sys KERNBUILDDIR=/usr/obj/usr/src/sys/X86_64_GENERIC kldload wlan; kldload wlan_acl; sysctl debug.use_malloc_pattern=1 kldload ./harness_mod.ko # exposes /dev/df0732 (0666) # as unprivileged user: cc -O2 -pthread -o trigger trigger.c && ./trigger 200000 4 # unpatched => panic cc -O2 -pthread -o leakcheck leakcheck.c && ./leakcheck 100000 4 # fixed => WEIRD_ADDR=0
Runtime reachability
The live ACL ioctl path needs a wlan(4) vap on a wifi radio β absent on this
KVM guest (ifconfig -l = vtnet0 lo0). The bug is proven at the object/harness
level (real acl_getioctl panic + leak) and via deterministic transcription. On
a wifi host with a vap, a local user could race ADDMAC vs MACCMD_LIST.
Fix
fix.diff: move ACL_LOCK before the as_nacls read, add M_ZERO, bound the
foreach. Validated: rebuilt wlan_acl.ko clean, reloaded, no panic + zero
WEIRD_ADDR residue.
Files
harness.cβ deterministic userspace transcription (PRIMARY proof)harness_mod.c/Makefileβ real-kernel object-level harness moduletrigger.cβ userspace racer (grow panic / shrink leak)leakcheck.cβ definitive WEIRD_ADDR residue classifierfix.diffβ git-apply-able fix (lock-before-read + M_ZERO + bounded foreach)VERDICT.mdβ full narrative + line-by-line analysis + before/after*.logβ full untrimmed build/run/panic/leak logs
DF-0732 β TOCTOU in wlan_acl acl_getioctl MACCMD_LIST
Verdict
REPRODUCED β heap OOB write (grow race) and uninitialized-heap info leak (shrink race), confirmed at two levels:
- Deterministic userspace harness (
harness.c) β transcribesacl_getioctlMACCMD_LIST verbatim with a controlled interleaving point between the unlockedas_naclsread andACL_LOCK. PrintsGROW RACE OOB WRITE CONFIRMEDandSHRINK RACE UNINIT LEAK CONFIRMED. - Real-kernel object-level harness (
harness_mod.ko+trigger.c/leakcheck.c) β exercises the actualacl_getioctlvia a fake vap +/dev/df0732, racingiac_add/iac_flushkthreads against the LIST ioctl. Produces a real kernel panicacl_getioctl+0xd6(grow-race OOB write faulting the page) and live shrink-race heap-residue leaks.
Fix VALIDATED (Phase 8): the fix.diff (lock-before-read + M_ZERO +
bounded foreach) rebuilds wlan_acl.ko clean (-Werror) and eliminates both
manifestations in the real kernel β no panic, zero WEIRD_ADDR residue.
Runtime reachability note (the realistic-threat caveat): the live 802.11
ACL ioctl path requires a wlan(4) vap on a parent wifi radio. This KVM audit
guest has no wifi radio (ifconfig -l = vtnet0 lo0; no ath/iwm/iwn;
wlan_acl is a loadable KLD, not in X86_64_GENERIC). So an unprivileged
runtime trigger is impossible on this guest; the bug is proven at the
object/harness level (real acl_getioctl panic + leak) and via deterministic
transcription. On a wifi-equipped host with a vap, a local user could race
SIOCS80211 ADDMAC vs SIOCG80211 MACCMD_LIST for OOB write / leak. This is
the same harness-precedent class as DF-0393/0594/0616/0753/0754.
The bug β line-by-line (sys/netproto/802_11/wlan_acl/ieee80211_acl.c)
acl_getioctl handles IEEE80211_MACCMD_LIST (:312-340):
| Line | Code | Problem |
|---|---|---|
| 313 | space = as->as_nacls * IEEE80211_ADDR_LEN; |
UNLOCKED read of as_nacls. ACL_LOCK is NOT held here. |
| 314-317 | if (ireq->i_len == 0) { i_len = space; return 0; } |
size-probe path (also uses the unlocked space). |
| 319-320 | ap = kmalloc(space, M_TEMP, M_INTWAIT); |
NO M_ZERO β buffer is uninitialized heap. |
| 327 | i = 0; |
|
| 328 | ACL_LOCK(as); |
Lock taken only NOW β after the size read AND after kmalloc. |
| 329-332 | TAILQ_FOREACH(acl, &as->as_list, acl_list) { ADDR_COPY(ap[i++].ml_macaddr, acl->acl_macaddr); } |
writes every current list entry; not bounded by space/ADDR_LEN. |
| 333 | ACL_UNLOCK(as); |
|
| 334-338 | copyout(ap, ireq->i_data, ...) |
ships ap to userland. |
ACL_LOCK/ACL_UNLOCK are real lockmgr(&as->as_lock, LK_EXCLUSIVE) locks
(ieee80211_dragonfly.h:606/619). acl_add (:199-215) and _acl_free
(:150-159) both mutate as_nacls/as_list under ACL_LOCK. So between
the unlocked read at :313 and the lock at :328, a concurrent ADDMAC/DELMAC
can change the list out from under the lister.
Grow race β heap OOB write (CWE-787)
Thread A (lister) reads as_nacls = N at :313, allocates N*6 bytes at
:319. Thread B (adder) inserts K MACs under the lock. Thread A takes the lock
at :328 and TAILQ_FOREACH writes N+K entries into the N*6-byte buffer:
ap[N..N+K-1] are written K*6 bytes past the end. The MAC bytes are
attacker-controlled (SIOCS80211 ADDMAC takes the MAC from userland). Real-kernel
proof: Fatal trap 12 ... supervisor write data, page not present ... Stopped at
acl_getioctl+0xd6: movw %si,0x4(%rcx) β the OOB write faulted into an unmapped
page.
Shrink race β uninitialized-heap info leak (CWE-908)
Thread A reads as_nacls = N, allocates N*6 bytes (no M_ZERO). Thread B
(flusher) clears the list to N-K. Thread A locks, TAILQ_FOREACH writes only
N-K entries; the tail K slots ap[N-K..N-1] are never written and hold
uninitialized heap residue. copyout ships all N*6 bytes to userland.
Real-kernel proof: [shrink-leak] ret_len=49152 entries=8192 ... bytes: 00 00 43
6f 70 79 ("..Copy" β kernel string residue), varying run-to-run.
Harness methodology
harness.c β deterministic userspace transcription (PRIMARY proof)
Faithfully transcribes acl_getioctl MACCMD_LIST with the data structures
(struct aclstate, struct ieee80211req_maclist = 6 bytes __packed,
ACL_LOCK = pthread mutex). A racer thread mutates the list at a controlled
interleaving point between the unlocked as_nacls read and the lock. A poisoned
allocator fills the slab + red-zone with 0xAA canary so OOB writes and uninit
tails are observable. Builds in two modes:
- cc -O2 -pthread -o harness harness.c β BUGGY transcription.
- cc -O2 -pthread -DFIXED -o harness_fixed harness.c β FIXED transcription
(lock-before-read + M_ZERO + bounded foreach).
Results (run.log): BUGGY β GROW RACE OOB WRITE CONFIRMED (24 OOB bytes for
N=8,K=4) + SHRINK RACE UNINIT LEAK CONFIRMED (4 uninit tail slots). FIXED β
both NOT TRIGGERED.
harness_mod.c + trigger.c / leakcheck.c β real-kernel object-level harness
harness_mod.ko (built against the running kernel) allocates a minimal fake
ieee80211vap, attaches the real "mac" aclator (wlan_acl.ko), exposes
/dev/df0732 (0666) whose ioctl calls acl->iac_getioctl(fake_vap, &ireq), and
runs adder + flusher kthreads that race the LIST path. The unprivileged
trigger/leakcheck drive it. This exercises the actual vulnerable kernel
function. kldload here loads the test harness, not an exploit β it is
primitive characterization of an otherwise-runtime-unreachable path (the
DF-0594/0616 object-harness precedent), not an escalation chain.
Results (panic.txt, leak_sample.txt, trigger_run.log): grow race β
acl_getioctl+0xd6 panic (OOB write); shrink race β live heap-residue leak
(kernel string "..Copy", varying bytes).
Exploit chain / impact ceiling
Primitive: attacker-controlled 6-byte heap writes into the slab object(s)
adjacent to the ap buffer (grow race); 6-byte uninit heap reads per shrunk
entry (shrink race). The ap buffer is kmalloc(N*6, M_TEMP); for typical N
this lands in kmalloc-128/256/512. Attacker controls N (list size) and the MAC
bytes written. On a noinv kernel this is a classic slab-groom β corrupt-adjacent
β escalate candidate (forge ucred/ops vector with no SMAP/SMEP/KASLR on this
guest). On default GENERIC, INVARIANTS slab checks (WEIRD_ADDR poisoning,
chunk_mark_allocated) catch the cross-slab corruption and panic β confirmed
by the real-kernel acl_getioctl+0xd6 trap.
Valid hard blocker (why no uid=0 here): the vulnerable runtime path
(SIOCG80211 MACCMD_LIST on a wlan vap) requires a wifi radio driver, which is
absent on this KVM guest. The primitive is therefore characterized at the
harness/object level (real acl_getioctl panic + leak, deterministic
transcription), not driven to a live unprivileged uid=0. On a wifi-equipped
host with a vap, this is a local-root candidate via slab grooming of the OOB
write; on this guest it is a confirmed DoS-panic + info leak.
Fix (fix.diff)
Three changes to acl_getioctl MACCMD_LIST, all targeting the root cause:
- Move
ACL_LOCK(as)BEFORE theas_naclsread (:313) so the size used for kmalloc and the list iterated byTAILQ_FOREACHcannot diverge. AddACL_UNLOCKon the early-return and ENOMEM paths.ACL_LOCKis a sleepable lockmgr lock, so holding it acrosskmalloc(M_INTWAIT)is safe. - Add
M_ZEROto thekmalloc(:319) (M_INTWAIT | M_ZERO) β kills the uninit-leak even if a future divergence reappears. - Bound the
TAILQ_FOREACHwrite loop tospace/IEEE80211_ADDR_LENentries (if (i >= bound) break;) β defense-in-depth so the loop can never write past the buffer.
git apply --check passes. The FreeBSD branch (#else) is given
IEEE80211_M_ZERO too for consistency.
Phase 8 β fix validation
Before (unpatched #0 baseline, prebuilt /boot/kernel/wlan_acl.ko):
- grow race β Fatal trap 12 ... acl_getioctl+0xd6: movw %si,0x4(%rcx) (panic,
guest down). (panic.txt)
- shrink race β [shrink-leak] ret_len=49152 ... bytes: 00 00 43 6f 70 79
(kernel string residue leaked). (leak_sample.txt, trigger_run.log)
After (rebuilt wlan_acl.ko from patched source, sha256 c23e324c...,
-Werror clean):
- grow race β no panic; 241489 LIST ioctls completed, guest stayed UP.
(fix_trigger_run.log)
- shrink race β leakcheck: WEIRD_ADDR residue = 0, OTHER = 0
(no heap residue leaked). (fix_run.log)
- Deterministic harness FIXED build β both races NOT TRIGGERED. (run.log,
fix_run.log)
fix_status: fixed. The fix closes both the OOB write and the info leak in the
real kernel and in the deterministic transcription.
PoC changes from the seeded version
The folder arrived with a prior runner's harness_mod.c / trigger.c / Makefile
(object-level harness) and their captured panic.txt / leak_sample.txt. This run:
- Re-verified the real-kernel panic (acl_getioctl+0xd6) and shrink-race
leak against the unpatched prebuilt module (refreshed panic.txt,
leak_sample.txt, new trigger_run.log).
- Added harness.c β a clean deterministic userspace transcription with a
poisoned allocator and grow/shrink modes (the PRIMARY proof per the task
framing).
- Added leakcheck.c β a definitive residue classifier that distinguishes
real WEIRD_ADDR (0xdeadc0de) heap residue from valid adder MACs, removing
the false positives in the original trigger.c's is_known_mac() (which
assumed adder byte3 always == 0xef).
- Authored fix.diff (lock-before-read + M_ZERO + bounded foreach) and
validated it end-to-end: git apply --check, rebuild wlan_acl.ko
(-Werror), reload, re-run trigger/leakcheck β no panic, zero residue.
- Added build.sh / run.sh repro scripts, refreshed build.log / run.log,
fix_build.log / fix_run.log / fix_trigger_run.log, env.txt.
Reproduce
# userspace deterministic harness (PRIMARY proof; no root, no wifi needed) cd findings/poc/DF-0732 && sh build.sh && sh run.sh # BUGGY: GROW RACE OOB WRITE CONFIRMED + SHRINK RACE UNINIT LEAK CONFIRMED # FIXED: both NOT TRIGGERED # real-kernel object-level harness (needs root to kldload the harness module) # kldload wlan; kldload wlan_acl; kldload ./harness_mod.ko # sysctl debug.use_malloc_pattern=1 # ./trigger 200000 4 # unpatched wlan_acl => panic (acl_getioctl+0xd6) # ./leakcheck 100000 4 # fixed wlan_acl => WEIRD_ADDR residue = 0
Fix verification
fixedVALIDATED. The fix closes BOTH manifestations. Baseline (unpatched prebuilt wlan_acl.ko, #0 kernel): grow race -> Fatal trap 12 / acl_getioctl+0xd6 panic (guest down); shrink race -> kernel string residue ('..Copy') leaked via copyout. Patched (wlan_acl.ko rebuilt from fix.diff source): grow race -> NO panic (241489 LIST ioctls, guest stayed UP); shrink race -> leakcheck WEIRD_ADDR residue = 0 (no heap residue leaked). The deterministic harness FIXED build independently confirms both races eliminated (GROW: red zone intact; SHRINK: all tail slots zeroed). git apply --check passes; module rebuilds -Werror clean.
BEFORE (baseline): 'Stopped at acl_getioctl+0xd6: movw %si,0x4(%rcx)' (panic) + '[shrink-leak] bytes: 00 00 43 6f 70 79' (kernel residue leak). AFTER (fixed wlan_acl.ko): 'trigger: 241489 LIST ioctls ... no panic' (guest UP) + 'leakcheck: WEIRD_ADDR residue : 0 (none -- leak eliminated)'. Deterministic harness before/after: BUGGY 'GROW RACE OOB WRITE CONFIRMED'/'SHRINK RACE UNINIT LEAK CONFIRMED' -> FIXED 'GROW RACE: NOT TRIGGERED'/'SHRINK RACE: NOT TRIGGERED'.
Confirmed kernel references
- sys/netproto/802_11/wlan_acl/ieee80211_acl.c:313
- sys/netproto/802_11/wlan_acl/ieee80211_acl.c:319
- sys/netproto/802_11/wlan_acl/ieee80211_acl.c:328
- sys/netproto/802_11/wlan_acl/ieee80211_acl.c:329
- sys/netproto/802_11/wlan_acl/ieee80211_acl.c:330
- sys/netproto/802_11/ieee80211_dragonfly.h:606
- sys/netproto/802_11/ieee80211.h:35
- sys/netproto/802_11/ieee80211_ioctl.h:329
Detail
Exploit chain
Memory-corruption primitive characterized, not driven to uid=0 due to a VALID hard blocker. Primitive: attacker-controlled 6-byte heap writes into the slab object(s) adjacent to the ap buffer (grow race; ap=kmalloc(N*6,M_TEMP) lands in kmalloc-128/256/512 for typical N; attacker controls N via list size and the MAC bytes via SIOCS80211 ADDMAC) plus 6-byte uninit heap reads per shrunk entry (shrink race, shipped by copyout). On default GENERIC the grow-race OOB trips INVARIANTS slab checks (WEIRD_ADDR 0xdeadc0de poisoning) and panics -- confirmed by the real acl_getioctl+0xd6 trap; on a noinv kernel this is a slab-groom -> corrupt-adjacent-victim -> escalate candidate (forge ucred/ops vector; no SMAP/SMEP/KASLR on this guest). VALID HARD BLOCKER: the vulnerable runtime path (SIOCG80211 MACCMD_LIST on a wlan vap) requires a wifi radio driver, which is ABSENT on this KVM guest (ifconfig -l = vtnet0 lo0; wlan_acl is a loadable KLD, not in X86_64_GENERIC). The primitive is therefore characterized at the harness/object level (real acl_getioctl panic + leak + deterministic transcription), not driven to a live unprivileged uid=0. On a wifi-equipped host with a vap, a local user racing ADDMAC vs MACCMD_LIST gets an OOB-write/leak primitive that is a local-root candidate via slab grooming. Files: harness.c (deterministic transcription, PRIMARY), harness_mod.c+trigger.c+leakcheck.c (real-kernel object-level harness). No live uid=0 is claimed -- the honest demonstrated impact on this guest is kernel panic (DoS) + info leak.
Evidence (decisive lines)
Deterministic harness (run.log): BUGGY grow -> 'GROW RACE OOB WRITE CONFIRMED' (foreach wrote 72 bytes into 48-byte buffer; 24 OOB bytes in red zone); BUGGY shrink -> 'SHRINK RACE UNINIT LEAK CONFIRMED' (4 tail slots uninitialized). Real-kernel (panic.txt): 'Fatal trap 12: page fault while in kernel mode / fault code = supervisor write data, page not present / Stopped at acl_getioctl+0xd6: movw %si,0x4(%rcx)'. Real-kernel shrink leak (leak_sample.txt): '[shrink-leak #1] ret_len=49152 entries=8192 first non-MAC at entry 2, bytes: 00 00 00 00 78 cb' and prior run captured kernel string residue '00 00 43 6f 70 79' ('..Copy'). FIXED harness: both races 'NOT TRIGGERED'. FIXED real-kernel module: 241489 LIST ioctls, no panic, guest UP; leakcheck WEIRD_ADDR residue=0.
PoC changes
Added harness.c (deterministic userspace transcription of acl_getioctl MACCMD_LIST with poisoned allocator + grow/shrink modes; PRIMARY proof per task framing). Added leakcheck.c (definitive WEIRD_ADDR 0xdeadc0de residue classifier that distinguishes real heap leaks from valid adder MACs, fixing the false-positive in the seeded trigger.c whose is_known_mac assumed adder byte3 always==0xef). Re-verified the prior harness_mod.c/trigger.c real-kernel harness against the unpatched prebuilt wlan_acl.ko: refreshed panic.txt (acl_getioctl+0xd6) and leak_sample.txt (kernel string residue). Authored fix.diff (ACL_LOCK before as_nacls read + M_ZERO + bounded foreach) and validated it end-to-end. Added build.sh/run.sh repro scripts, refreshed build.log/run.log, new fix_build.log/fix_run.log/fix_trigger_run.log/env.txt, VERDICT.md, README.md, manifest.json.
Verified recommended fix
In acl_getioctl IEEE80211_MACCMD_LIST (sys/netproto/802_11/wlan_acl/ieee80211_acl.c:312-340): (1) move ACL_LOCK(as) to BEFORE the as_nacls read at :313 so the kmalloc size and the TAILQ_FOREACH list cannot diverge (add ACL_UNLOCK on the i_len==0 early-return and the ENOMEM paths; ACL_LOCK is a sleepable lockmgr lock so holding it across kmalloc(M_INTWAIT) is safe); (2) add M_ZERO to the kmalloc at :319 (M_INTWAIT | M_ZERO) to kill the uninit-leak; (3) bound the TAILQ_FOREACH write loop to space/IEEE80211_ADDR_LEN entries (defense-in-depth). The FreeBSD #else branch gets IEEE80211_M_ZERO too. Supersedes the finding markdown proposal (which named the same three changes; this fix.diff is the verified, git-apply-able, line-accurate implementation).
Verdict
REPRODUCED. The TOCTOU in acl_getioctl MACCMD_LIST is real and confirmed at two levels. (1) Line-by-line trace of sys/netproto/802_11/wlan_acl/ieee80211_acl.c: as_nacls is read at :313 WITHOUT ACL_LOCK (lock not taken until :328); kmalloc(space,M_TEMP,M_INTWAIT) at :319 has NO M_ZERO; TAILQ_FOREACH ap[i++] at :329-332 writes every current list entry, unbounded; copyout at :335 ships ap to userland. ACL_LOCK/UNLOCK are real lockmgr LK_EXCLUSIVE (ieee80211_dragonfly.h:606). No guard was missed. (2) Deterministic userspace harness (harness.c) transcribes this verbatim with a controlled interleaving point and prints 'GROW RACE OOB WRITE CONFIRMED' (24 OOB bytes for N=8,K=4) and 'SHRINK RACE UNINIT LEAK CONFIRMED' (4 uninit tail slots). (3) Real-kernel object-level harness (harness_mod.ko exercising the ACTUAL acl_getioctl via a fake vap + /dev/df0732, driven by unprivileged trigger.c) reproduced a real kernel panic 'Stopped at acl_getioctl+0xd6: movw %si,0x4(%rcx)' (grow-race OOB write faulting the page) and live shrink-race heap-residue leaks ('..Copy' kernel string, varying bytes).
No comments yet.