{
  "finding_id": "DF-3562",
  "status": "reproduced",
  "reproduced": 1,
  "impact": "none",
  "confidence": "certain",
  "verdict": "serpent_set_key() (sys/crypto/serpent/serpent.c:451-474) validates only key_len > 256; with negative key_len the u_int32_t locals i/lk wrap ((u32)((key_len+31)/32) ~= 0xFFFFFFFF for key_len <= -63 -> runaway linear OOB write of l_key[i] sourced from OOB key-buffer reads; i = (u32)(key_len/32) = 0xFFFFFFFF for key_len in [-63,-32] -> single wild RMW at +16GiB; non-multiple-of-8 lengths read up to 3 bytes past the key buffer). All three variants demonstrated live on the guest from a verbatim /usr/src build (3/3 fault demos, SIGBUS/SIGSEGV with si_addr evidence in run.log). NOT reachable in-tree: the only caller chain (cryptoapi.c serpent_cbc_setkey:826 / serpent_xts_setkey:928) validates 128/192/256 (256/512 halved) first, so impact=none today - defense-in-depth parity with the twofish twins DF-0965/DF-2371. Two-line fix validated: 3/3 -> 0/3 faults, 6349-vector KAT corpus still clean.",
  "exploit_chain": "",
  "evidence": "run.log (serpoob section: 3/3 fault demonstrations with per-child si_code/si_addr), fix.diff + fix_run.log (0/3 faults after the fix, KATs 6349/0), verification/serpent/serptest + kats_serpent.txt (correctness), VERDICT.md (full narrative incl. reachability analysis and the other three files verification)",
  "kernel_refs": [
    "sys/crypto/serpent/serpent.c:451",
    "sys/crypto/serpent/serpent.c:453",
    "sys/crypto/serpent/serpent.c:456",
    "sys/crypto/serpent/serpent.c:459",
    "sys/crypto/serpent/serpent.c:461",
    "sys/crypto/serpent/serpent.c:472",
    "sys/crypto/serpent/serpent.c:474",
    "sys/crypto/cryptoapi/cryptoapi.c:826",
    "sys/crypto/cryptoapi/cryptoapi.c:928"
  ],
  "poc_changes": "Seed concept was a 4-byte-before-the-array write via l_key[-1]; live debugging showed the real primitive is u_int32_t wraparound (i/lk) producing a ~16GiB runaway fill loop or a +16GiB wild index access - serpoob.c was rewritten with signal-reporting children (si_code/si_addr) and a guard-page OOB-read case; harness also fixed: v4 KAT hex typo, Linux-vector reinterpretation (0-bit key / 16-byte key), replacement of a buggy self-written reference implementation with the Botan verified vector corpus (169 vectors).",
  "attempts": 5,
  "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": 5100,
  "guest_dirty": 0,
  "build_cmd": "cd /tmp/DF-3562 && ./build.sh (stages verbatim /usr/src sources; only kernel-only headers redirected to shims, recorded in verification/chachapoly/prep.sh)",
  "run_cmd": "cd /tmp/DF-3562 && ./run.sh (all four harnesses + serpoob; exit 0)",
  "code_hash": "e2b4050fe54c4a036498a937e8210e6749b0e491f85b7596f5c448e9069d1cb5",
  "fix_status": "fixed",
  "fix_baseline_reproduced": 1,
  "fix_patched_reproduced": 0,
  "fix_verdict": "fix.diff adds the missing lower-bound/byte-multiple check to serpent_set_key(); applied to a verbatim /usr/src copy, rebuilt and re-run on the guest: baseline 3/3 OOB fault demonstrations -> 0/3 after the fix, 6349-check KAT corpus unchanged. No kernel rebuild performed: the only in-tree caller (cryptoapi) pre-validates keylen, so no kernel code path can reach the changed line - the harness builds the identical function source.",
  "fix_evidence": "fix.diff, fix_build.log, fix_run.log",
  "notes": "Anchor pack for the 4-file pass-2 batch: serpent.c (6349 checks 0 fails + this finding), twofish.c (15018 checks 0 fails, clean), rijndael-api-fst.c (208 checks 0 fails, dead in-kernel code, known DF-0968/DF-0969 confirmed live as records), chachapoly.c (22 checks 0 fails + live wg(4) loopback tunnel 220/220 packets). Harness false alarms investigated and killed: chacha/poly1305 mismatches were src_len-without-tag and non-zeroed in-place keystream bugs in the harness; cross-verified against a pure-Python RFC 8439 oracle.",
  "recommended_fix": "serpent.c:456: replace `if (key_len > 256)` with `if (key_len < 0 || key_len > 256 || (key_len & 7))` (see fix.diff)"
}