{
  "finding_id": "DF-5728",
  "status": "reproduced",
  "reproduced": true,
  "impact": "panic",
  "confidence": "certain",
  "verdict": "REPRODUCED 2/2 boots on the stock with-src kernel: a single DDB console line p  + 60 ( (and 40 ( on a second boot) drives db_terms unbounded tLPAREN recursion (db_expr.c:84-95; 272 bytes of kernel stack per level, measured from /boot/kernel/kernel) through the interrupted contexts 16 KB kernel stack guard page -> DOUBLE FAULT - KERNEL STACK GUARD HIT! / panic: double fault -> crashdump, guest dead. Run 1 rip=db_unary+0xc (pure descent, 60 levels=16.3KB), run 2 rip=db_force_whitespace+0xc (the db_error->db_printf path at depth 40 after the descent itself survived) - both rsp page-aligned on the guard page. The lexers 120-char line cap allows 118 levels = 32.1 KB, roughly twice the stack, so the trigger is deterministic. Controls: depth 30 survives (8.2 KB), balanced nesting and a 117-frame unary chain evaluate normally, clean session exit. Threat model is the DDB console actor (serial terminal server / IPMI / hypervisor console) - privileged-adjacent, availability-only, hence Low severity consistent with DF-2238/2239/2241. NOT uid0_privesc: the guard page converts the overflow into a clean panic; no silent adjacent-kernel-memory corruption observed, and the console actor already has call/write/reset by DDB design.",
  "exploit_chain": "",
  "evidence": "run1-fullserial.log (sanity 7 -> 30-paren Syntax error survives -> 60-paren DOUBLE FAULT with full frames); run2-sweep.serial.log (fresh boot: 40-paren DOUBLE FAULT, rip=db_force_whitespace+0xc, rsp page-aligned); panic.txt (both fatal frames + measured frame budget); run3-controls.serial.log (balanced-20=1, unary-117=-1, clean exit); postfix-run.log (Expression too deep at 60 and 118, no panic, healthy ps walk); build.log (patched kernel build); fix.diff (DB_MAX_EXPR_DEPTH=16 + db_flush_lex reset, git-apply-able, APPLIES-CLEAN)",
  "kernel_refs": [
    "sys/ddb/db_expr.c:84",
    "sys/ddb/db_expr.c:85",
    "sys/ddb/db_expr.c:106",
    "sys/ddb/db_expr.c:225",
    "sys/ddb/db_lex.c:42",
    "sys/ddb/db_lex.c:117",
    "sys/ddb/db_command.c:472",
    "sys/ddb/db_sysctl.c:75",
    "sys/platform/pc64/x86_64/trap.c:420",
    "sys/cpu/x86_64/include/param.h:UPAGES"
  ],
  "poc_changes": "No seed PoC. Built from scratch: socket-serial QEMU rig (adapted from DF-5561/DF-5721 pattern), paced serial DDB driver, sysctl DDB entry, threshold battery. Note: bare ( lines never reach the parser (db_command rejects non-ident first tokens with ?) - the bomb must be p  + parens; DF-2238s off-by-two (full 120-char line) was deliberately avoided by using 118-paren lines in the max-depth test.",
  "attempts": 4,
  "guest_uname": "DragonFly dfbsd 6.5-DEVELOPMENT DragonFly 6.5-DEVELOPMENT #0: Thu Jul 2 06:02:54 UTC 2026 x86_64 (baseline); patched #1: Sat Oct 10 19:33:50 UTC 2026",
  "runtime_sec": 2700,
  "guest_dirty": 0,
  "build_cmd": "(trigger: none - pure DDB console input; rig: ./serial_vm.sh up) | fix build: cd /usr/src && make -j6 nativekernel KERNCONF=X86_64_GENERIC && make installkernel KERNCONF=X86_64_GENERIC",
  "run_cmd": "dfbsd-qemu/vm.sh run_root sysctl debug.enter_debugger=ddb & sleep 8; DF5728_SOCK=/tmp/opencode/df-5728-ser.sock ./drive_ddb.py \"$(python3 -c print(\"p \"+\"(\"*60+\"1\"))\" 8",
  "code_hash": "2ad6943d98fb7bb705852a894c4d7ff54d31e8e7b309bfe97b9d155fbb179c78",
  "notes": "Impact ceiling honestly assessed as panic/dos, not corruption: x86_64 DFly kernel stacks are guard-paged on this kernel, so the overflow faults cleanly (both runs show rsp page-aligned at the guard). Crashdumps from runs 1-2 were discarded by the with-src snapshot reverts; serial logs carry the decisive frames. Post-DDB-exit soft-wedge observed on BOTH stock (run 3) and patched (run 4) kernels after clean c exits - pre-existing guest/DDB-exit fragility (DF-5722 family), orthogonal to this finding and to the fix. Guest was reset to with-src and powered off after evidence capture.",
  "recommended_fix": "Cap db_expression() nesting at DB_MAX_EXPR_DEPTH=16 (~4.4 KB worst case) and reset the depth counter in db_flush_lex() so db_error() longjmps cannot leave it stale (fix.diff, validated: baseline panic gone, Expression too deep returned, controls pass).",
  "fix_status": "fixed",
  "fix_baseline_reproduced": true,
  "fix_patched_reproduced": false,
  "fix_verdict": "fix.diff applied in guest /usr/src, kernel rebuilt (make nativekernel, build.log) and installed; identical rig and identical bomb lines (60 and 118 parens) produce Expression too deep with the db> prompt returning and the session continuing through five further commands including a full ps walk - no panic, no double fault. Controls on the patched kernel: p (1+(2*3))=7, balanced-8 nesting evaluates, 117-frame unary chain evaluates. Known cost: balanced nesting deeper than 16 now errors on legal-but-pathological input.",
  "fix_evidence": "findings/poc/DF-5728/fix.diff; findings/poc/DF-5728/postfix-run.log; findings/poc/DF-5728/build.log"
}