DF-3568 / verdict.json
{ "finding_id": "DF-3568", "status": "reproduced", "reproduced": 1, "impact": "none", "confidence": "certain", "verdict": "rijndael_set_key (rijndael-api.c:38-43) is a void wrapper that passes keyBits to rijndaelKeySetupEnc/Dec unvalidated; the only guard is the algs KASSERT (alg-fst.c:738), compiled out on production kernels. Demonstrated in-guest with -DNDEBUG (production semantics) via the same-source userland-object pattern: (a) bits=64 with an 8-byte key faults at key+8 - the rk[0..3]/rk[4..7] loads (alg-fst.c:740-785) read up to 32 bytes of key material before any keyBits branch; (b) bits=64 with a safe buffer silently yields Nr=0, and the subsequent rijndael_encrypt runs the r=Nr>>1 loop (alg-fst.c:951-979) with r going negative - a wild round-key walk that segfaults (exit 139; panic-class in kernel). Impact is none today: both in-tree callers validate (ccmp_setkey requires wk_keylen==16 at ieee80211_crypto_ccmp.c:134-141; cryptoapi validates 128/192/256 and XTS halves at cryptoapi.c:308-320,398-403). Filed as Info hardening of the API contract (void return, assert-only guard) for future callers. Fix validated at harness level: rejecting invalid bits without reading key plus Nr-invariant guards in encrypt/decrypt removes both the overread and the wild walk, with FIPS-197 128/192/256 KATs still passing.", "exploit_chain": "", "evidence": "guard.log: FAULT-CONFIRMED: sig=11 si_addr=0x800477000 (== key+8) and safe-mode Segmentation fault ... exit=139 (Nr=0 wild walk); fixval.log: guard mode exit 0, safe mode exit 0, rijkat_fixed RESULT-PASS: 0 failures; run.log: FIPS-197 C.1/C.2/C.3 PASS + in-guest LibreSSL aes-ecb byte-identical cross-match", "kernel_refs": [ "sys/crypto/rijndael/rijndael-api.c:38", "sys/crypto/rijndael/rijndael-alg-fst.c:738", "sys/crypto/rijndael/rijndael-alg-fst.c:740", "sys/crypto/rijndael/rijndael-alg-fst.c:784", "sys/crypto/rijndael/rijndael-alg-fst.c:814", "sys/crypto/rijndael/rijndael-alg-fst.c:951", "sys/crypto/rijndael/rijndael-alg-fst.c:979", "sys/netproto/802_11/wlan_ccmp/ieee80211_crypto_ccmp.c:134", "sys/crypto/cryptoapi/cryptoapi.c:308" ], "poc_changes": "No seed PoC existed; authored guard_rij_badbits.c (guard + safe modes) and rijkat.c. Compile fix en route: DragonFly siginfo_t uses si->si_addr and _exit needs unistd.h. Note: the safe-mode print text predates fix semantics - with the fix, rijndael_encrypt returns early leaving ct untouched (the exit=0 and absence of SIGSEGV is the decisive signal).", "attempts": 2, "guest_uname": "DragonFly dfbsd 6.5-DEVELOPMENT DragonFly 6.5-DEVELOPMENT #0: Thu Jul 2 06:02:54 UTC 2026 root@dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC x86_64", "runtime_sec": 420, "guest_dirty": 0, "build_cmd": "cc -O2 -DNDEBUG -I /usr/src/sys -o guard_rij_badbits guard_rij_badbits.c /usr/src/sys/crypto/rijndael/rijndael-api.c /usr/src/sys/crypto/rijndael/rijndael-alg-fst.c", "run_cmd": "./guard_rij_badbits guard; ./guard_rij_badbits safe # expect FAULT exit 42 + segv exit 139 baseline; fixed builds exit 0", "code_hash": "63863df59e16f03d11cdf19d9812878e56750a159c26598b32c771fa464c1a5a", "notes": "Phase V scope: Info hardening - full guest Phase V not contractually required, but in-guest correctness verification was requested and subsumed the primitive demo and fix validation. Guest ASan runtime is broken (unresolved __asan_* symbols); deterministic guard-page SIGSEGV with si_addr used instead. The Nr=0 wild walk is additionally the mechanism behind the safe-mode segfault - documented as panic-class if ever reached in kernel context. ccmp ctx is M_ZERO-kmalloced (ccmp.c:103-104) and cryptoapi randomizes+frees-with-explicit_bzero its ctx (cryptoapi.c:1084,1097-1098), so uninitialized-ctx garbage-Nr is not reachable either.", "recommended_fix": "rijndael-api.c: reject keyBits not in {128,192,256} before touching key material and have rijndael_encrypt/decrypt refuse schedules with Nr not in {10,12,14} (see fix.diff).", "fix_status": "fixed", "fix_baseline_reproduced": 1, "fix_patched_reproduced": 0, "fix_verdict": "fix.diff applied to a source copy (never sys/): guard mode prints BUG-NOT-PRESENT exit 0 (no key read for invalid bits), safe mode exit 0 (encrypt refuses Nr=0, wild walk gone), and rijkat_fixed still passes all FIPS-197 vectors. Harness-level validation only (no kernel build) - justified because no in-tree caller can deliver invalid bits today.", "fix_evidence": "fixval.log: BUG-NOT-PRESENT: survived bits=64 with 8-byte key exit=0; safe exit=0; rijkat_fixed RESULT-PASS: 0 failures" } |