DragonFlyBSD Kernel Audit
DF-0640 / fix_run.log
← back to finding ↓ download raw
=== 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