DF-3364 / verdict.json
{ "finding_id": "DF-3364", "status": "reproduced", "reproduced": 1, "impact": "leak", "confidence": "certain", "verdict": "tdma_isfull() (ieee80211_scan_sta.c:965) indexes tdma_inuse[slot>>3] for slot up to the attacker-controlled slotcnt-1 (255) although the array is one byte inside an IE that can be as short as 6 bytes; with the TDMA IE last in a 64-byte blob the kernel read tdma_inuse[31] = IE byte 44 = 30 bytes past the heap allocation, and that bytes content flipped the candidate decision: 0x00 groom -> clear at slot 254 -> fail=0x0 -> C ACCEPTED; 0xff groom -> FULL -> fail=0x1000 -> C REJECTED. Proven with kprintf instrumentation inside the real tdma_isfull/match_bss on an otherwise-stock kernel (probe-only patch); gcc -Warray-bounds independently flags the same index as out-of-bounds. Post-fix (fix.diff kernel #2) all short TDMA IEs are rejected as malformed and the full-length valid IE (test 17) is accepted.", "exploit_chain": "unauthenticated beacon to an AHDEMO+TDMA vap (root-created, driver with C_TDMA) -> short TDMA-OUI vendor IE saved verbatim in the blob -> ies_expand exposes tdma_ie (len>=4 only) -> match_bss reads tdma_version/slot past minimal IEs -> tdma_isfull scans 248 attacker-directed bitmap bytes beyond the allocation -> OOB heap bytes decide candidate acceptance. Oracle-grade; no write primitive.", "evidence": [ "run.log: DBG isfull: ... slotcnt=255 inuse[0]=ff inuse[31]=00 / clear at slot 254 (byte +44) -> ACCEPTED vs inuse[31]=ff / FULL / fail=0x1000 -> REJECTED", "../DF-3363/fix_validation.log: post-fix TDMA matrix (17 accepted, 11/12/14 rejected as malformed)", "build.log excerpt in VERDICT: gcc -Werror=array-bounds rejects tdma_inuse[31] as above array bounds" ], "kernel_refs": [ "sys/netproto/802_11/wlan/ieee80211_scan_sta.c:959", "sys/netproto/802_11/wlan/ieee80211_scan_sta.c:965", "sys/netproto/802_11/wlan/ieee80211_scan_sta.c:1016", "sys/netproto/802_11/wlan/ieee80211_scan_sta.c:1023", "sys/netproto/802_11/ieee80211_input.h:118", "sys/netproto/802_11/wlan/ieee80211_node.c:1001" ], "poc_changes": "same harness as DF-3363 plus: TDMA vap must be created via wlanmode tdma (ifconfig clone flag IEEE80211_CLONE_TDMA); Cs rates must include 11 Mbps (the TDMA vap pins ucastrate=2*11 via TDMA_TXRATE_11B_DEFAULT); IEEE80211_SCAN_NOJOIN used so the selection verdict is observable without driving the TDMA join state machine (which hangs on the fake radio); the flaky early runs were background-scan se_notseen bumps, fixed by re-injecting C right before scan_end.", "attempts": 8, "guest_uname": "DragonFly dfbsd 6.5-DEVELOPMENT #1 Fri Sep 11 12:28:18 UTC 2026 (instrumented, logic stock) for baseline; #2 fixed kernel for validation", "runtime_sec": 3600, "guest_dirty": 0, "build_cmd": "sh findings/poc/DF-3364/build.sh", "run_cmd": "ifconfig wlan create wlandev fws0 wlanmode tdma up; sysctl kern.fwscan_test=11|12|14|17", "code_hash": "54859c80a66d25ec2d056f0dec66495fd2fc3b3c665fe93c13f0283adf0f847f", "notes": "Reachability needs AHDEMO+TDMA (config-dependent) - hence Low severity despite certain code defect. match_bss also dereferences vap->iv_tdma without a NULL check when iv_caps has C_TDMA (driver forgot tdma_vattach) - covered by the same fix.diff (ts==NULL guard).", "recommended_fix": "require tdma_len >= sizeof(struct ieee80211_tdma_param)-2 before reading fields, clamp slotcnt to 8*nitems(tdma_inuse); see fix.diff.", "fix_status": "fixed", "fix_kernel_uname": "DragonFly dfbsd 6.5-DEVELOPMENT #2 Fri Sep 11 12:44:59 UTC 2026", "fix_baseline_reproduced": 1, "fix_patched_reproduced": 0, "fix_verdict": "with fix.diff, the 12-byte TDMA IE variants (11/12/14) are all rejected (MATCH_TDMA_NOIE) regardless of heap groom; the full-length valid IE (17) is accepted. No OOB-dependent behavior remains.", "fix_evidence": "findings/poc/DF-3363/fix_validation.log" } |