DF-5475 / verdict.json
{ "finding_id": "DF-5475", "status": "reproduced", "reproduced": true, "impact": "dos", "confidence": "certain", "verdict": "Reproduced on the first attempt on the stock X86_64_GENERIC kernel: entering the kernel debugger in GDB mode with no gdb console attached (gdb_tab == NULL, the normal state on hardware without a flag-0x80 sio port / dcons) makes gdb_handle_exceptions first putpacket() fault at putpacket+0x2c reading 0x68 = &((struct consdev*)0)->cn_gdbprivate, and the trap_fatal -> kdb_trap(db_active) -> stub re-entry loop floods Fatal trap 12 forever: no ddb fallback, no dump, no reboot, permanent whole-machine hang. Source-wise the -1 sentinel of getDebugChar is masked into data (& 0x7f == 0x7f) by every wait loop (x86_64-gdbstub.c:189,200,277), so even with the guards intact the ack wait can never exit; in the shipped gcc8.3 binary the constprop clone of putpacket additionally deleted the NULL guards, giving the hard fault. One-guard fix (early return when gdb_tab == NULL) validated: patched kernel takes the same trigger through a complete clean stop/restart cycle with zero faults and returns rc 0 (fully clean on -smp 1; fault-storm eliminated on -smp 6 as well, where an unrelated pre-existing SMP Xcpustop artifact subsequently wedged userland - documented separately in VERDICT.md).", "exploit_chain": "", "evidence": "serial.baseline.txt (stop banners then eternal identical Fatal trap 12, fault va 0x68, rip ffffffff80b940ac = putpacket+0x2c); run.log (TRIGGER_RC=124, GUEST_ANSWERS=NO, QEMU_PROCESS=alive); stock-kernel disassembly of putpacket.constprop.2 at 0xffffffff80b94080 showing the unguarded mov 0x68(%rax) with gdb_tab @ 0xffffffff8131dd20; serial.control.txt (ddb branch reaches db> prompt - differential); build.log + serial.patched.txt (patched kernel: guard is instruction #1 of gdb_handle_exception, trigger returns rc 0 on -smp 1).", "kernel_refs": [ "sys/cpu/x86_64/misc/x86_64-gdbstub.c:147", "sys/cpu/x86_64/misc/x86_64-gdbstub.c:156", "sys/cpu/x86_64/misc/x86_64-gdbstub.c:189", "sys/cpu/x86_64/misc/x86_64-gdbstub.c:277", "sys/cpu/x86_64/misc/x86_64-gdbstub.c:448", "sys/cpu/x86_64/misc/x86_64-gdbstub.c:531", "sys/platform/pc64/x86_64/db_interface.c:105", "sys/platform/pc64/x86_64/db_interface.c:179", "sys/ddb/db_sysctl.c:57", "sys/dev/serial/sio/sio.c:3131", "sys/platform/pc64/x86_64/trap.c:1096" ], "poc_changes": "Seed concept (silent putpacket spin) corrected to the observed primitive: the shipped binarys constprop clone drops the accessor NULL guards, so the first T-reply putpacket NULL-derefs at offset 0x68 and the machine dies in an unterminating fault-retry storm (trap.c:1096 re-entry). Trigger uses the production debug.enter_debugger=gdb sysctl (db_sysctl.c:57-74) instead of a KLD harness; no crafted packets are involved.", "attempts": 4, "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": 4800, "guest_dirty": 0, "build_cmd": "guest: cd /usr/src && make nativekernel KERNCONF=X86_64_GENERIC && make installkernel KERNCONF=X86_64_GENERIC (fix.diff applied first; baseline needs no build)", "run_cmd": "findings/poc/DF-5475/run.sh (vm.sh run_root sysctl debug.enter_debugger=gdb, 60s timeout)", "code_hash": "d2f5bc97d3b77cbe9890a04a81ffa31dc36a1430b005447057cefc2aecb9d1e9", "notes": "Threat: boot -g (RB_GDB) without a gdb console, or root sysctl debug.enter_debugger=gdb; then any kernel panic / debugger entry = permanent hang (remote crasher converts recoverable panic into unrecoverable hang). Availability-only, config-conditional => Low. Open adjacent issue found during validation, outside this file: after a fast kdb stop/return cycle on -smp 6 KVM, other CPUs stop answering IPIs (follow-up NMI stop_cpus never completes - apic_vector.s Xcpustop machinery); deserves its own finding. Guest returned to clean snapshot (vm.sh reset with-src); files row already marked audited pass 2.", "recommended_fix": "Early-return from gdb_handle_exception when gdb_tab == NULL (fix.diff); belt-and-braces alternative in the caller: db_interface.c:105 ddb_mode = !(boothowto & RB_GDB) || gdb_tab == NULL so the box falls back to DDB on its console.", "fix_status": "fixed", "fix_baseline_reproduced": true, "fix_patched_reproduced": false, "fix_verdict": "fixed", "fix_evidence": "build.log (patch applied, -Werror build OK, guard = first instruction of gdb_handle_exception in installed kernel); serial.patched.txt + run.patched.log (identical trigger on patched kernel: full stop/restart cycle, zero faults, sysctl returns rc 0, machine alive - fully clean on -smp 1; on -smp 6 the DF-5475 fault storm is equally absent and kdb_trap returns, with an unrelated pre-existing SMP Xcpustop artifact documented in VERDICT.md)" } |