⬢ DragonFlyBSD Kernel Audit
DF-3568 / verdict.json
← back to finding ↓ download raw
{
  "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"
}