β¬’ DragonFlyBSD Kernel Audit
← triage Β· dashboard
DF-1400

Stack buffer overflow in wi_write_wep LUCENT WEP-key load (wk_keylen up to 16 copied into wi_keydat[14])

Summary

wi_write_wep at if_wi.c:1751-1769: LUCENT branch memcpy(wkey[i].wi_keydat, wk_key, keylen). wi_keydat is u8[14] (if_wavelan_ieee.h:293). wk_keylen from net80211 up to IEEE80211_KEYBUF_SIZE=16 (bounded by ioctl, WEP cipher accepts >=5 no max). keylen 15-16 -> 1-2B past wi_keydat. i==3 (last slot) -> off wkey[4] stack array into frame. Triggered on state transition (AUTH/RUN) calling wi_write_wep. SYSCAP_NONET_WIFI required. Fix: clamp keylen to sizeof(wi_keydat).

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-1400 Β· 10 files
FileTypeDescriptionSize
wi_overflow.c trigger-source byte-exact harness replicating wi_write_wep LUCENT keylen overflow 3.9 KB view raw
build.sh build-script cc -O2 -o wi_overflow wi_overflow.c 78 B view raw
run.sh run-script run harness 24 B view raw
run.log run-log decisive harness output, OVERFLOW CONFIRMED 820 B view raw
env.txt environment uname, cc version 227 B view raw
fix.diff suggested-fix clamp keylen to sizeof(wi_keydat) 502 B view raw
VERDICT.md verdict full analysis 4.0 KB ↓ raw
README.md readme reproduce guide 1.5 KB ↓ 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
README.md readme reproduce guide
↓ download raw

DF-1400 β€” wi_write_wep LUCENT WEP-key stack overflow (PoC)

Summary

wi_write_wep LUCENT branch (sys/dev/netif/wi/if_wi.c:1766-1769) does memcpy(wkey[i].wi_keydat, wk_key, keylen) with keylen up to IEEE80211_KEYBUF_SIZE=16 into wi_keydat[14], overflowing by 1-2 bytes per slot; on the last slot (i==3) the overflow runs off the wkey[4] stack array into the frame. Triggered on a WiFi state transition (AUTH/RUN) calling wi_write_wep. Requires SYSCAP_NONET_WIFI.

Reachability

wi(4) is a loadable module (if_wi.ko), not in GENERIC, attaching only to Prism/Lucent WiFi cards. The QEMU guest has no WiFi hardware, so the bug is not live-reachable here. Proven deterministically with a byte-exact harness replicating struct wi_key (if_wavelan_ieee.h:290-292) and the wkey[4] stack array.

Build / run

./build.sh && ./run.sh

Expected output (bug present)

slot 3: wrote 16 bytes into 14-byte wi_keydat -> 2 byte(s) past end [runs OFF the wkey[4] array into the frame]
frame region after wkey[4] corrupted by last slot: YES
OVERFLOW CONFIRMED: keylen=16 > wi_keydat[14] overflows by 2 byte(s) per slot ...

On a fixed driver the copy is bounded to sizeof(wi_keydat) = 14.

Fix

Clamp keylen to sizeof(wkey[i].wi_keydat) before the memcpy (fix.diff). Validated to compile into a rebuilt if_wi.ko (-Werror, rc=0).

Files

  • wi_overflow.c β€” byte-exact harness.
  • build.sh / run.sh / run.log / env.txt / fix.diff / VERDICT.md / manifest.json.
VERDICT.md verdict full analysis
↓ download raw

DF-1400 β€” wi_write_wep LUCENT WEP-key stack overflow

Verdict: REPRODUCED (primitive proven via source trace + byte-exact harness). Fix compiles.

wi_write_wep (LUCENT firmware branch) copies a WEP key of up to IEEE80211_KEYBUF_SIZE=16 bytes into a 14-byte wi_keydat field with no bounds check, overflowing by 1-2 bytes per key slot; on the last slot (i==3) the overflow runs off the wkey[4] stack array into the surrounding frame. Confirmed real by source tracing + a byte-exact harness. Not live-reachable on the QEMU guest because wi(4) attaches only to Prism/Lucent WiFi hardware (absent in QEMU) and the code is a loadable module. The fix compiles cleanly (-Werror).

Mechanism (trigger β†’ primitive β†’ effect)

sys/dev/netif/wi/if_wi.c:1764-1769 (LUCENT branch):

struct wi_key wkey[IEEE80211_WEP_NKID];                 /* wkey[4] on stack */
...
memset(wkey, 0, sizeof(wkey));
for (i = 0; i < IEEE80211_WEP_NKID; i++) {
    keylen = vap->iv_nw_keys[i].wk_keylen;              /* up to 16 */
    wkey[i].wi_keylen = htole16(keylen);
    memcpy(wkey[i].wi_keydat, vap->iv_nw_keys[i].wk_key, keylen);   /* SINK */
}

Destination (sys/dev/netif/wi/if_wavelan_ieee.h:290-292):

struct wi_key {
    u_int16_t  wi_keylen;
    u_int8_t   wi_keydat[14];      /* <-- 14-byte destination */
};
  • IEEE80211_KEYBUF_SIZE = 16 (sys/netproto/802_11/ieee80211_crypto.h:34), IEEE80211_WEP_NKID = 4 (ieee80211.h:1272).
  • wk_keylen is bounded by the ioctl path to IEEE80211_KEYBUF_SIZE (16); the WEP cipher accepts >=5 with no upper bound, so 15-16 reaches here.
  • memcpy of 16 bytes into wi_keydat[14] overflows by 2 bytes. For i==3 (the last slot), the overflow runs off the wkey[4] array into the stack frame.

Primitive

  • Class: stack buffer overflow, 1-2 bytes per slot (keylen 15-16), attacker-controlled key material content; on the last slot the overflow escapes the wkey[4] array into the surrounding frame.
  • Trigger: WiFi state transition (AUTH/RUN) that calls wi_write_wep.
  • Effect: stack corruption in the LUCENT WEP-key write path β†’ panic or potential control-flow corruption on real Prism/Lucent WiFi hardware.

Reachability / threat model

  • wi is a loadable module (if_wi.ko), NOT in X86_64_GENERIC. It attaches only to Prism/Lucent IEEE 802.11 WiFi cards. The QEMU guest has no WiFi hardware, so wi_write_wep never runs live here.
  • Realistic threat: a host with Prism/Lucent WiFi joining a crafted/rogue AP, or a malicious local user triggering a WEP key set on attached WiFi that transitions to AUTH/RUN. Requires SYSCAP_NONET_WIFI.
  • Validated the primitive deterministically with the byte-exact harness (wi_overflow.c): keylen=16 into wi_keydat[14] overflows by 2 bytes per slot; the last slot (i==3) corrupts the frame canary.

Harness proof (run.log)

wi_key.wi_keydat capacity: 14 bytes
keylen (wk_keylen, up to IEEE80211_KEYBUF_SIZE): 16
slot 3: wrote 16 bytes into 14-byte wi_keydat -> 2 byte(s) past end [runs OFF the wkey[4] array into the frame]
frame region after wkey[4] corrupted by last slot: YES
OVERFLOW CONFIRMED: keylen=16 > wi_keydat[14] overflows by 2 byte(s) per slot; last slot overruns wkey[4] into the stack frame.

Fix validation

fix.diff clamps keylen to sizeof(wkey[i].wi_keydat) (=14) before the memcpy. The fix was applied to in-guest /usr/src and the if_wi.ko module rebuilt cleanly (cc ... -Werror, RC=0). Runtime re-test is not possible on this guest (no WiFi HW), so fix_status = not_testable for runtime, with the diff verified to apply + compile and the harness logic confirming the clamp bounds the copy to 14 bytes.

Kernel references

Fix verification

not_testable

compile+harness validated

module build rc=0

Confirmed kernel references

β€”

Detail

Exploit chain

none

Evidence (decisive lines)

β€”

Verdict

REPRODUCED (harness). wi_write_wep LUCENT keylen=16 vs wi_keydat[14] -> 2B overflow per slot. wi.ko module, no WiFi HW.