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

twofish_set_key performs no key-length validation enabling stack/struct OOB writes and mk_tab corruption on out-of-range key_len_bits

Summary

twofish_set_key derives ctx->k_len=key_len_bits/64 with no check key_len_bits is {128 192 256}. For oversized key_len_bits (k_len>=5) key-expansion loop writes past size-4 stack arrays me_key[]/mo_key[] and past s_key[4] into mk_tab[] and reads past caller key buffer. For key_len_bits<=0 loop skipped gen_mk_tab switch falls through leaving mk_tab uninitialised (heap info-leak source). Code defect is genuine memory-corruption primitive currently NOT reachable from any unprivileged syscall because every in-kernel caller (twofish_cbc_setkey twofish_xts_setkey) whitelists key length before calling. Latent/defense-in-depth gap becomes High-severity corruption if future caller forgets to validate. Related to DF-0965. [VERIFIED pass2: reproduced - key_len_bits 320 writes s_key 4 into mk_tab 0 and leaves schedule stale, 0 keeps previous key active, userspace twin SIGSEGVs on in_key guard page and smashes callee frame at k_len 16; length-refusal fix-validated, all in-tree callers pre-validate]

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-2371 Β· 13 files
FileTypeDescriptionSize
build.log β€” 62 B view raw
build.sh β€” 86 B view raw
env.txt β€” 412 B view raw
fix.diff β€” 380 B view raw
rig β€” 4.0 KB ↓ download
run.log β€” 112 B view raw
run.sh β€” 161 B view raw
run_fixed.log β€” 96 B view raw
run_fixed_kernel.log β€” 2.8 KB view raw
run_kernel_baseline.log β€” 172 B view raw
twofish_rig.c β€” 4.4 KB view raw
verdict.json β€” 2.3 KB view raw
fix.diff β€” 380 B view raw

Fix verification

not_testable
↓ fix.diffper-fix-DF-2371

Confirmed kernel references

Detail

Evidence (decisive lines)

session baseline + run_fixed_kernel.log (setkey320: mk_tab[0]=ce22885b vs cafebabe, mk_tab[1] stale; setkey0: k_len=0, stale schedule), run.log + run_fixed.log (twin: keyread/stacksmash fault then clean), fix.diff

PoC changes

none; kernel KAT digest 57ff739d4dc92c1b... cross-checked between kernel and userspace twin (identical), the quoted 256-bit KAT suffix in the rig comment was from memory and is superseded by the twin comparison

Verified recommended fix

refuse key_len_bits outside {128,192,256} at the top of twofish_set_key

Verdict

Real in-kernel twofish_set_key with out-of-range key_len_bits: 320 (k_len=5) writes s_key[4] into mk_tab[0] (struct order l_key, s_key, mk_tab) - observed as the magic mk_tab[0] changing while gen_mk_tab switch(5) falls through leaving the rest stale - and 0 leaves the previous key schedule in place (k_len=0, mk_tab from keyA) while l_key is re-derived from uninitialized me_key/mo_key stack. The userspace twin of the verbatim file shows the harder primitives directly: key_len_bits=2048 walks in_key reads 256 bytes into a guard page (SIGSEGV) and k_len=16 smashes the callee frame (SIGBUS on return). With the length check both kernel scenarios leave the ctx untouched (k_len stays 4, magic intact) and the twin stops faulting. All in-tree callers (twofish_cbc_setkey/twofish_xts_setkey in cryptoapi.c:670/:770) pre-validate, so this is a latent API landmine - as filed.