DF-0640 / fix_run.log
=== DF-0640: ieee80211_crypto_decap minlen ignores hdrlen ===
NOTE: Requires WiFi hardware — bug confirmed by source trace.
Harness demonstrates the minlen bypass and double-free path.
IEEE80211_WEP_MINLEN (buggy) = 32 (hardcodes sizeof(ieee80211_frame)=24)
[Test 1] QoS frame (hdrlen=26, len=34):
crypto_decap(hdrlen=26, pkthdr.len=34):
minlen check: pkthdr.len=34 >= MINLEN=32 -> PASSED
m_copydata at offset hdrlen+3 = 29
m_pullup for hdrlen+cip_header = 26 + 8 = 34
[Test 2] 4-addr QoS frame (hdrlen=32, len=33):
-> Buggy check passes (33 >= 32), correct would reject (33 < 40)
crypto_decap(hdrlen=32, pkthdr.len=33):
minlen check: pkthdr.len=33 >= MINLEN=32 -> PASSED
[BUG] CORRECT minlen would be 40 (hdrlen=32) -> SHOULD reject but DIDN'T
m_copydata at offset hdrlen+3 = 35
m_copydata: OOB! off=35+len=1 > pkthdr.len=33
-> OOB READ / PANIC!
-> IMPACT 1: OOB read -> kernel panic
[Test 3] QoS frame (hdrlen=26, len=33):
-> Buggy check passes (33 >= 32), correct would reject (33 < 34)
crypto_decap(hdrlen=26, pkthdr.len=33):
minlen check: pkthdr.len=33 >= MINLEN=32 -> PASSED
[BUG] CORRECT minlen would be 34 (hdrlen=26) -> SHOULD reject but DIDN'T
m_copydata at offset hdrlen+3 = 29
m_pullup for hdrlen+cip_header = 26 + 8 = 34
m_pullup: fails (pkthdr.len=33 < requested=34) -> FREES mbuf, returns NULL
-> m_pullup failed, mbuf FREED, function returns NULL
-> CALLER still holds original m -> m_freem(m) -> DOUBLE-FREE!
-> IMPACT 2: DOUBLE-FREE (caller will m_freem the freed mbuf)
=== SUMMARY ===
hdrlen from ieee80211_hdrspace varies (QoS=26, 4-addr=30/32).
Buggy MINLEN uses hardcoded 24, admitting frames too short for ops.
Impact 1: m_copydata OOB -> panic (INVARIANTS) or NULL deref
Impact 2: m_pullup fail -> mbuf freed -> caller double-free
(mbuf double-free is a well-known code-exec primitive)
Fix: use hdrlen in the minlen check.
RUN_EXIT=0