⬢ DragonFlyBSD Kernel Audit
DF-3565 / verdict.json
← back to finding ↓ download raw
{
  "finding_id": "DF-3565",
  "status": "reproduced",
  "reproduced": 1,
  "impact": "none",
  "confidence": "certain",
  "verdict": "The kernel DES entry point ships with des_check_key=0 (sys/crypto/des/des_setkey.c:65) and nothing in-tree ever enables it, so des_set_key() (des_setkey.c:142-153) always takes the unchecked path: the 16-entry weak/semi-weak table and parity validation that the file correctly implements are dead code by default. Demonstrated live: des_set_key(0x0101010101010101) returns 0 (accepted) with the stock default, and returns -2 once the default is flipped. The detection machinery and the key schedule themselves verified correct (weak table exact vs 4096 random + 16 near-miss negatives; 2666 schedules ECB cross-matched against LibreSSL 3.6.1 both directions). Reachability is privileged-only (root-configured cryptoapi SAs / legacy smb_crypt NTLM-derived keys), an attacker cannot choose the key, so impact is a fail-open validation default on a legacy algorithm rather than an exploitable primitive.",
  "exploit_chain": "",
  "evidence": "run.log, default policy section: des_set_key(0x0101010101010101) rc=0 (0=ACCEPTED) [des_check_key=0] inside an otherwise all-green 8916-check run (parity table, weak-key detection when enabled, schedule-vs-libcrypto). fix_run.log: patched default -> rc=-2 via the same default path.",
  "kernel_refs": [
    "sys/crypto/des/des_setkey.c:65",
    "sys/crypto/des/des_setkey.c:142",
    "sys/crypto/des/des_setkey.c:159",
    "sys/crypto/des/des_setkey.c:97",
    "sys/crypto/des/des_setkey.c:171",
    "sys/netproto/smb/smb_crypt.c"
  ],
  "poc_changes": "Harness written from scratch (des_kat.c). Two environment quirks handled: (1) openssl/des.h and the kernel crypto/des/des.h share the HEADER_DES_H include guard, so the two needed libcrypto DES symbols are declared manually; (2) a memorized classic DES anchor constant (3fa40e8a984d4815) turned out to belong to a different key/plaintext pair and was dropped - the authoritative cross-check is the libcrypto agreement, which matched on all 2666 keys (the correct classic pair key=133457799BBCDFF1 pt=0123456789ABCDEF -> 85E813540F0AB405 passed as hardcoded anchor).",
  "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": 412,
  "guest_dirty": 0,
  "build_cmd": "cd findings/poc/DF-3565 && ./build.sh",
  "run_cmd": "cd findings/poc/DF-3565 && ./run.sh",
  "code_hash": "e8c2883200dbed07e93bd06f4685ddb5e8332178dc7029a5e2a5aad4ea4b5e99",
  "notes": "Associated hygiene (not separately filed): des_set_key_unchecked keeps key-derived register material (c,d,s,t,t2) on the stack after return; no verbatim key copy is made. Same class as DF-3564, much weaker exposure. Guest left clean.",
  "recommended_fix": "Default des_check_key to 1 (fail-closed) and audit consumers for parity assumptions; see fix.diff.",
  "fix_status": "fixed",
  "fix_baseline_reproduced": 1,
  "fix_patched_reproduced": 0,
  "fix_verdict": "One-character default flip des_check_key=1 (des_setkey.c:65). Baseline: weak key 0101010101010101 accepted rc=0 by the default des_set_key path. Patched copy of the same source: rc=-2 (rejected via parity+weak checks); all 8915 other checks unchanged. The lone reported FAIL in the patched run is the harnesss acceptance assertion inverting, i.e. the fix taking effect.",
  "fix_evidence": "fix_run.log: === DF-3565 fix validation === -> des_set_key(0x0101010101010101) rc=-2 ... [des_check_key=1] contrasted with the baseline line in run.log.",
  "fix_kernel_uname": "DragonFly dfbsd 6.5-DEVELOPMENT #0: Thu Jul  2 06:02:54 UTC 2026 (userland same-source validation; kernel unchanged)"
}