DF-5724 / verdict.json
{ "finding_id": "DF-5724", "status": "reproduced", "verdict": "set $tabstops=0 followed by any DDB output (the next db> prompt suffices, via db_readlines db_force_whitespace sync at db_input.c:306) executes rounddown(x,0) in db_force_whitespace (db_output.c:80, NEXT_TAB at :65, rounddown sys/sys/param.h:400) -> fatal trap 18 cascade (31 traps, RIP db_force_whitespace+0x26 = 0xffffffff802cba26, ~0x370 kernel stack consumed per trap) ending in an unrecoverable brick; set $tabstops=-8 makes the same loop spin forever with all CPUs stopped (silent hard hang, zero traps). Both reproduced live on the stock kernel via the socket-serial DDB rig; fix.diff (validating db_varfcn_t setters + defensive NEXT_TAB ternary) validated on a rebuilt kernel: both variants rejected with tabstops must be >= 1, previously-fatal commands work, session alive, zero traps.", "reproduced": true, "impact": "panic", "confidence": "certain", "exploit_chain": "jailed root (DF-2246 reachability: sysctl debug.enter_debugger=ddb) -> set $tabstops=0 -> integer divide fault in DDB -> trap handler re-divides while printing -> 31x fatal trap 18 cascade eats the kernel stack -> whole host bricked (hard reset only). Variant B: set $tabstops=-8 -> non-advancing whitespace loop -> silent all-CPU hang. DoS only; no privilege or memory primitive.", "evidence": "serial.variantA.log (31x Fatal trap 18, RIP 0xffffffff802cba26 = db_force_whitespace+0x26 symbolized in env.txt); serial.variantB.log (transcript ends at db> after set $tabstops=-8, zero traps, ssh dead); serial.fixedkernel.log (both variants rejected, print/d 5 works, zero traps); fix.diff; build.log", "kernel_refs": [ "sys/ddb/db_output.c:65", "sys/ddb/db_output.c:74", "sys/ddb/db_output.c:80", "sys/ddb/db_output.c:82", "sys/ddb/db_variables.c:51", "sys/ddb/db_variables.c:52", "sys/ddb/db_variables.c:120", "sys/ddb/db_variables.c:126", "sys/ddb/db_input.c:306", "sys/sys/param.h:400", "sys/ddb/db_command.c:481" ], "poc_changes": "Trigger reworked vs intuition: no explicit printing command is needed \u2014 the pending trailing space of the next db> prompt fires db_force_whitespace via db_readlines sync (db_input.c:306) before any echo; variant B likewise hangs before echoing anything. Driver paces <=8 bytes/150ms (guest UART RX FIFO 16) and uses one persistent socket with continuous drain.", "attempts": 3, "guest_uname": "DragonFly dfbsd 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": 1500, "guest_dirty": 0, "build_cmd": "stock: none (serial ddb session). fix: scp fix.diff dfbsd:/tmp; cd /usr/src && patch -p1 -N < /tmp/fix.diff && make -j6 nativekernel KERNCONF=X86_64_GENERIC && make installkernel (BUILD_RC=0, kernel #1 Sat Oct 10 17:53:17 UTC 2026)", "run_cmd": "./run.sh A (then guest reset) ./run.sh B (then reset; fixed-kernel rerun identical)", "code_hash": "4e71cb5ce013d9095ddfb7ff8a65cbf0c0747f6a74da9b35d5ad2b4c57ce432a", "notes": "Same session controls: x/x db_active prints normally before each set. Guest reset with-src after validation. Huge tabstops values (0x7fffffffffffffff) wrap (i)+width negative -> same non-advancing loop as variant B.", "recommended_fix": "Validating db_varfcn_t setters for $tabstops/$maxwidth (reject <1 via db_error, which longjmps before the store) + defensive db_tab_stop_width>0 ternary in NEXT_TAB.", "fix_status": "fixed", "fix_baseline_reproduced": true, "fix_patched_reproduced": false, "fix_verdict": "Baseline stock kernel: variant A = 31-trap fatal cascade + brick; variant B = silent all-CPU hang. Patched kernel (fix.diff, rebuilt + installed + rebooted): both variants print tabstops must be >= 1, x/x db_active and print/d 5 (the exact B trigger) execute normally, DDB session continues, c resumes \u2014 zero fatal traps. Bad behavior gone.", "fix_evidence": "serial.fixedkernel.log (rejected + working output + alive session, 0 Fatal trap occurrences); build.log (BUILD_RC=0, install completed); fix.diff" } |