β¬’ 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 65 B view raw
run.sh run-script run harness 89 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.3 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 status (batch validation)

Applied with the 36 sibling fix.diffs of this batch in findings/poc/_batch41/all_fixes.patch; single in-guest make -j6 nativekernel KERNCONF=X86_64_GENERIC completed RC=0 with zero errors under -Werror (full log: findings/poc/_batch41/fix_build8.log). Behavior A/B intentionally skipped for this Info-tier item.

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.