DF-5721 / verdict.json
{ "finding_id": "DF-5721", "status": "reproduced", "reproduced": true, "impact": "none", "confidence": "certain", "verdict": "DDB software watchpoints (`watch`) are inert on x86_64: live-verified that a 4-byte watch on the every-tick-written kernel global `ticks` never stops the kernel (ticks advanced to 0xb342 with the watch listed as armed, machine alive), because the pmap RO protection (db_watch.c:226-229) faults as a plain page fault that vm_fault() silently rewires writable, while the watchpoint classifier the resume choreography needs is dead code (db_find_watchpoint #ifdef notused, db_watch.c:241-273) and IS_WATCHPOINT_TRAP is hardwired 0 (db_machdep.h:67), making the watchpt arm of db_restart_at_pc (db_run.c:199-206) unreachable. Root-console-only surface (unprivileged probes all negative), no memory unsafety: Low severity, debugger-correctness defect that leaves an operator debugging with a dead instrument.", "exploit_chain": "", "evidence": "watch-desync.serial.log (db> watch ticks / c / machine alive / second session: ticks: b342 advancing, show watches lists it, zero stops); README.md root-cause chain with path:line; unpriv-probes.log (all reachability probes negative); fix.diff refuses the feature on x86_64", "kernel_refs": [ "sys/ddb/db_run.c:199", "sys/ddb/db_run.c:206", "sys/ddb/db_run.c:208", "sys/ddb/db_trap.c:54", "sys/ddb/db_watch.c:218", "sys/ddb/db_watch.c:241", "sys/cpu/x86_64/include/db_machdep.h:67", "sys/platform/pc64/x86_64/trap.c:629" ], "poc_changes": "No seed PoC existed. Built the rig from scratch: socket-serial QEMU guests (serial_vm.sh SMP / serial_vm1.sh UP), a paced serial-line DDB driver (drive_ddb.py), and three unprivileged reachability probes (probe_int3.c, probe_step.c, probe_dbregs.c) compiled on the guest.", "attempts": 3, "guest_uname": "DragonFly dfbsd 6.5-DEVELOPMENT #0 Thu Jul 2 06:02:54 UTC 2026 x86_64", "runtime_sec": 480, "guest_dirty": 0, "build_cmd": "cc -O0 -o probe_int3 probe_int3.c && cc -O0 -o probe_step probe_step.c && cc -O0 -o probe_dbregs probe_dbregs.c (on guest; DDB sessions need no build)", "run_cmd": "./serial_vm1.sh up; ssh dfbsd sysctl debug.enter_debugger=ddb & ; ./drive_ddb.py watch ticks 4 c 6 # then re-enter and inspect x/x ticks + show watches", "code_hash": "d2ddfc831df07815aad62268d74dafffd091bac78ffa1e8ddcc391f1cdee803a", "notes": "Full implementation fix = resurrect db_find_watchpoint in the kernel page-fault path plus a real IS_WATCHPOINT_TRAP; fix.diff ships the safe refuse-on-x86_64 variant. The watch was initially suspected in the interrupt-context resume panic; bisect (DF-5722) proved it innocent.", "recommended_fix": "Refuse software watchpoints on x86_64 (define DB_NO_SOFTWARE_WATCHPOINTS in db_machdep.h, reject in db_watchpoint_cmd) until a real watchpoint trap classifier exists; point users at hwatch.", "fix_status": "not_testable", "fix_baseline_reproduced": true, "fix_patched_reproduced": false, "fix_verdict": "fix.diff authored post-verification against the read-only sys/ tree; not applied/rebuilt (kernel rebuild infeasible in-run on the 1-vCPU validation guest; Low-severity feature-disable, not memory corruption, so rebuild validation is not mandatory per contract).", "fix_evidence": "findings/poc/DF-5721/fix.diff" } |