DF-5517 / verdict.json
{ "finding_id": "DF-5517", "status": "reproduced", "reproduced": true, "impact": "dos", "confidence": "certain", "verdict": "Production-code request-sequence proof: the unmodified ubser.c (md5-gated) is compiled into a KLD harness and the real static ubser_cfg_set_break() runs on a real usb_process taskqueue with the exact ucom_cfg_line_state arithmetic (usb_serial.c:1384-1420). The full open -> TIOCSBRK -> TIOCCBRK -> close lifecycle sends exactly ONE device command, VENDOR_SET_BREAK (0x02); the clear command is NEVER sent on any path -- PHASE L sequence = { 0x02 }, PHASE D (direct set_break(1); set_break(0) on a live port) = { 0x02 }, VENDOR_CLEAR_BREAK (0x03) NEVER OBSERVED, because the request lives inside `if (onoff) (ubser.c:470) with no else-leg and the constant at ubser.c:102 has exactly one occurrence in the file (its #define, grep proof in build.log). Consequence: once a break is set on a BWCT port, the devices line stays broken until the adapter is power-cycled; TIOCCBRK and close are silent kernel-side no-ops and all subsequent TX on the port is garbled (functional kill of the port, fails open). Upstream-inherited (FreeBSD ubser has the identical shape). fix.diff (else-leg sending VENDOR_CLEAR_BREAK, wValue=portno, bounded 250 ms) rebuilt and rerun on the guest: both phases observe { 0x02, 0x03 }; tree restored md5-verified.", "exploit_chain": "any tty opener (root via ttyU* 0600, group dialer via cuaU* 0660, usb_serial.c:477-488) issues TIOCSBRK once -> VENDOR_SET_BREAK (0x02) reaches the device -> TIOCCBRK/close send nothing (ubser.c:470 gate, ubser.c:102 dead constant) -> the BWCT ports TX line remains in break indefinitely -> every later write(2) on the port transmits garbage until the adapter is physically replugged", "evidence": "run.log/run.2.log: PHASE L lifecycle request sequence = { 0x02 } (1 request(s); VENDOR_CLEAR_BREAK=0x03 NEVER OBSERVED) and PHASE D direct set+clear request sequence = { 0x02 } (...); build.log grep proof VENDOR_CLEAR_BREAK occurrences in ubser.c: 1 (definition only: YES); run.fixed.log: both sequences = { 0x02, 0x03 } (0x03 OBSERVED)", "kernel_refs": [ "sys/bus/u4b/serial/ubser.c:99-102", "sys/bus/u4b/serial/ubser.c:462-487", "sys/bus/u4b/serial/ubser.c:470-486", "sys/bus/u4b/serial/usb_serial.c:1190-1197", "sys/bus/u4b/serial/usb_serial.c:1401-1420" ], "poc_changes": "No seed PoC existed; authored from scratch (DF-5447 production-include + DF-5515 rig). Bring-up fixes: (1) kernel TU has no memchr -- replaced with a scan loop; (2) neutered ubser_driver/ubser_devclass statics must be referenced (touch function) or -Wunused kills the build; (3) the direct-clear phase must run on a LIVE taskqueue so the sinks usb_proc_is_gone gate (usb_request.c:771) passes as in production.", "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": 700, "guest_dirty": 0, "build_cmd": "sh /root/df5517/src/build.sh (in-tree kmod at /usr/src/sys/bus/u4b/serial/ub5517, -Werror clean; prints the reference-count grep proof)", "run_cmd": "sh /root/df5517/src/run.sh (kldload /root/df5517/ub5517clrbrk.ko; kldunload; dmesg | grep UB5517)", "code_hash": "32433755711ede5e46ee39717be4483f577a9a69892749fe9ad7a8da36690b04", "notes": "Guest left pristine (ubser.c md5 restored, harness dirs removed, modules unloaded). Severity Low: functional/port-availability defect for tty openers, no kernel memory-safety impact, fails open. Upstream-inherited from FreeBSD -- candidate for an upstream joint fix.", "recommended_fix": "Add the missing else-leg to ubser_cfg_set_break() sending VENDOR_CLEAR_BREAK (wValue=portno) with a bounded 250 ms timeout (full diff in fix.diff; validated: clear now OBSERVED).", "fix_status": "fixed", "fix_baseline_reproduced": 1, "fix_patched_reproduced": 1, "fix_verdict": "fix.diff applied to the guests /usr/src ubser.c (guest patch(1), hunk #1 @482); same production-code harness rebuilt -Werror-clean and re-run: PHASE L = { 0x02, 0x03 } and PHASE D = { 0x02, 0x03 } -- VENDOR_CLEAR_BREAK OBSERVED, the clear path exists. git apply --check passes on the audited repo; guest tree restored and md5-verified.", "fix_evidence": "fix.diff; fix_build.log (RC=0); run.fixed.log (VENDOR_CLEAR_BREAK=0x03 OBSERVED in both phases); VERDICT.md Fix validation section" } |