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

ccmp_setkey omits AES key load for software-decrypt-only keys, causing kernel panic on first received frame

Summary

ccmp_setkey (:140): if(k->wk_flags&IEEE80211_KEY_SWENCRYPT) rijndael_set_key gates ONLY on SWENCRYPT(0x0010). ccmp_decap (:266-268): if(k->wk_flags&IEEE80211_KEY_SWDECRYPT)&&!ccmp_decrypt calls ccmp_decrypt when SWDECRYPT(0x0020) set. If key has SWDECRYPT WITHOUT SWENCRYPT (hardware-encrypt/software-decrypt config reachable via driver-flag override ieee80211_crypto.c:386-410) AES key schedule NEVER loaded. ccmp_attach kmallocs M_ZERO (:104) so Nr=0 ek[]/dk[] all zero. ccmp_decrypt->ccmp_init_blocks->rijndael_encrypt with Nr=0: rijndaelEncrypt (rijndael-alg-fst.c:947 #else branch) r=Nr>>1=0 for(;;){--r} never==0 loop never breaks rk+=8 walks past ek[60] then dk[60] then past ccmp_ctx into adjacent kernel heap -> page fault panic. Panic occurs in ccmp_init_blocks BEFORE MIC check so attacker need not forge valid MIC any privacy-bit-set data frame >=32B triggers. Attacker: WiFi peer sends single protected 802.11 data frame to victim BSS/STA whose driver configures CCMP SWDECRYPT-only (hardware TX crypto + host RX decrypt). No auth needed panic during CBC-MAC block construction. Impact: hard kernel panic complete DoS. Confidence likely: SWDECRYPT-only config may be uncommon (most drivers both HW or both SW) but code path reachable by framework. Fix: gate on IEEE80211_KEY_SWCRYPT (SWENCRYPT|SWDECRYPT).

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-0654 Β· 8 files
FileTypeDescriptionSize
fix.diff suggested-fix gate rijndael_set_key on IEEE80211_KEY_SWCRYPT (SWENCRYPT|SWDECRYPT) 487 B view raw
VERDICT.md verdict full source trace + rijndael Nr=0 runaway-loop argument 4.5 KB ↓ raw
build.sh build-log no-op (source-only) 158 B view raw
run.sh run-log no-op (no WiFi HW); checks fix.diff applies 598 B view raw
env.txt environment guest uname 365 B view 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
live_reachability_check.txt reachability-test Live wifi reachability evidence - no wifi HW 1.3 KB view raw
VERDICT.md verdict full source trace + rijndael Nr=0 runaway-loop argument
↓ download raw

DF-0654 β€” ccmp_setkey omits AES key load for software-decrypt-only CCMP keys

Verdict: BUG CONFIRMED REAL by source trace β€” not runnable on guest (no WiFi hardware); impact ceiling = deterministic kernel panic (DoS)

Bug summary (source-confirmed)

ccmp_setkey() (sys/netproto/802_11/wlan_ccmp/ieee80211_crypto_ccmp.c:130) loads the AES key schedule only when IEEE80211_KEY_SWENCRYPT (0x0010) is set:

129  static int
130  ccmp_setkey(struct ieee80211_key *k)
...
134      if (k->wk_keylen != (128/NBBY)) { ... return 0; }
140      if (k->wk_flags & IEEE80211_KEY_SWENCRYPT)            // <-- gates ONLY on SWENCRYPT
141          rijndael_set_key(&ctx->cc_aes, k->wk_key, k->wk_keylen*NBBY);
142      return 1;
143  }

But ccmp_decap() calls ccmp_decrypt() when IEEE80211_KEY_SWDECRYPT (0x0020) is set (ieee80211_crypto_ccmp.c:266-268), and ccmp_decrypt() β†’ ccmp_init_blocks() β†’ rijndael_encrypt() uses the same ctx->cc_aes.

ccmp_attach() (:97-104) allocates the context with M_ZERO, so if a key is configured SWDECRYPT without SWENCRYPT, ccmp_setkey skips rijndael_set_key and cc_aes stays zeroed: Nr == 0, ek[]/dk[] all zero.

In rijndaelEncrypt() (sys/crypto/rijndael/rijndael-alg-fst.c:862), with Nr=0:

946   rk += Nr << 2;        // rk unchanged
951   r = Nr >> 1;          // r = 0
952   for (;;) {
953       ... read rk[4..7]; rk += 8;
979       if (--r == 0) break;   // --r => -1, NEVER == 0 -> loop never breaks
...

--r makes r == -1 (never 0), so the loop never terminates; rk += 8 each iteration walks rk past ek[60], dk[60], out of the ccmp_ctx and into adjacent kernel heap. The Te0[(s0>>24)] lookups index on out-of-bounds memory and rk[] reads eventually hit an unmapped page β†’ fatal page fault.

This fault occurs inside ccmp_init_blocks() (CBC-MAC block construction) before any MIC check, so an attacker need only deliver a single privacy-bit-set 802.11 data frame (>=32 B) to a BSS/STA whose driver configures CCMP SWDECRYPT-only.

Reachability of the SWDECRYPT-without-SWENCRYPT config

ieee80211_crypto.c::ieee80211_crypto_newkey(): - :320-325 β€” if the hardware lacks the cipher, it sets both SWCRYPT bits (flags |= IEEE80211_KEY_SWCRYPT), so the AES key IS loaded β€” NOT the vulnerable case. - :386-410 β€” the driver-flag override path: after dev_key_alloc(), if the driver changed wk_flags (e.g. a driver doing HW-encrypt / SW-decrypt asymmetric offload), the cipher context is re-attached with the driver's flags. A driver that clears SWENCRYPT while keeping SWDECRYPT yields the vulnerable state where ccmp_setkey skips the key load but ccmp_decap still decrypts.

So the buggy state is reachable via the framework's driver-override path; whether it manifests depends on a driver setting SWDECRYPT-without-SWENCRYPT (uncommon but within the framework's design β€” asymmetric crypto offload).

Reproduction

Not runnable on this guest: there is no WiFi hardware / ieee80211 VAP, so the CCMP cipher is never attached and ccmp_setkey/ccmp_decap cannot be invoked. This is a source/logic finding verified by code trace + the mathematically-certain rijndaelEncrypt Nr=0 runaway-loop argument. (The #else /* !FULL_UNROLL */ branch at rijndael-alg-fst.c:947 is the one compiled by the DragonFly build.)

Fix

Gate the AES key load on IEEE80211_KEY_SWCRYPT (= SWENCRYPT|SWDECRYPT) so the key schedule is loaded whenever EITHER software path is used (fix.diff):

-   if (k->wk_flags & IEEE80211_KEY_SWENCRYPT)
+   if (k->wk_flags & IEEE80211_KEY_SWCRYPT)
        rijndael_set_key(&ctx->cc_aes, k->wk_key, k->wk_keylen*NBBY);

Matches the finding proposal (gate on SWCRYPT). IEEE80211_KEY_SWCRYPT is defined at sys/netproto/802_11/ieee80211_crypto.h:107-108.

Kernel references

Fix verification

not_testable

not_applicable: no WiFi HW

Confirmed kernel references

Detail

Exploit chain

none β€” HW-gated.

Evidence (decisive lines)

ccmp_setkey in kernel: YES
ccmp_decap in kernel: YES
Requires wlan interface with CCMP key -> needs wifi HW -> absent

PoC changes

Added live_reachability_check.txt.

Verified recommended fix

fix.diff ensures rijndael_set_key is called whenever SWENCRYPT or SWDECRYPT is set. Matches finding proposal.

Verdict

INCONCLUSIVE (HW-gated, source-confirmed). ccmp_setkey (0xffffffff80758790) and ccmp_decap (0xffffffff807589d0) ARE compiled into the kernel. The bug (AES key schedule never initialized when key has SWDECRYPT without SWENCRYPT) is traced line-by-line. BUT: ccmp_setkey/ccmp_decap are called through the ieee80211_crypto key framework, which requires a wlan interface with CCMP encryption configured. No wifi HW on QEMU guest.