DF-5515 / verdict.json
{ "finding_id": "DF-5515", "status": "reproduced", "reproduced": true, "impact": "dos", "confidence": "certain", "verdict": "Mechanism-level reproduction with production code verbatim: the unmodified ubser.c (md5-gated) is compiled into a KLD harness and the real static ubser_cfg_set_break() (ubser.c:462-487) runs on a real usb_process taskqueue (usb_proc_create, usb_serial.c:322) with only the EP0 sink modeled. Measured (hz=100): a silent evil BWCT adapter makes the single TIOCSBRK request eat its full 1000 ms timeout (error discarded, ubser.c:482-485) -- close(2) behind it blocked uninterruptibly (usb_proc_mwait, usb_serial.c:671-672) for 914 ms; five paced SBRK/CBRK pairs kept the per-adapter taskqueue continuously occupied 5.7 s (sustained loops extend without bound); the slow-answer variant SUCCEEDS at timeout-100 ms and blocks the closer 818 ms with no error visible anywhere. The drivers entire cfg surface is this ONE request (no cfg_open/close/param callbacks, ubser.c:175-184; open issues 0 requests), so this is the family minimum -- same shape as DF-5487 uvisor / DF-5504 ucycom. Unplug stalls identically via ucom_detach -> usb_proc_drain (usb_serial.c:394) on the USB hub event thread. Local amplification is bounded by tty permissions (0600/0660, usb_serial.c:477-488); the evil device needs nothing. fix.diff (timeout 1000 -> 250 ms at ubser.c:481) rebuilt and rerun on the guest: closer block 91 ms vs 914 ms -- stall GONE; tree restored md5-verified.", "exploit_chain": "attacker supplies an evil BWCT USB adapter (manufacturer string BWCT + vendor-specific interface, ubser.c:215-217) -> ttyU*/cuaU* nodes created -> a tty opener (root or group dialer) issues TIOCSBRK -> ucom_cfg_line_state (usb_serial.c:1415-1417) runs ubser_cfg_set_break on the ucom taskqueue -> device NAKs the VENDOR_SET_BREAK data stage -> 1 s of serialized cfg-thread occupancy per ioctl; concurrent close(2) of any of the adapters ttys blocks uninterruptibly behind the same queue; unplug (hub event thread) drains it too; a sustained >=1 s-paced break loop pins the taskqueue without bound", "evidence": "run.log: UB5515[A]: ... EP0 bRequest=0x02 (1000 ms timeout): device silent -- NAKs until timeout + closer: unblocked ELAPSED=914 ms; run.log phase B: 5 requests, line-state tasks 205->5933 ms continuous; run.2.log: ELAPSED=799 ms (B2 stability); run.fixed.log: ELAPSED=91 ms (fix validated); build.log: -Werror-clean production-code build", "kernel_refs": [ "sys/bus/u4b/serial/ubser.c:462-487", "sys/bus/u4b/serial/ubser.c:480-485", "sys/bus/u4b/serial/ubser.c:175-184", "sys/bus/u4b/serial/usb_serial.h:220-221", "sys/bus/u4b/serial/usb_serial.c:322", "sys/bus/u4b/serial/usb_serial.c:671-672", "sys/bus/u4b/serial/usb_serial.c:394", "sys/bus/u4b/serial/usb_serial.c:1356-1421", "sys/bus/u4b/usb_request.c:760-790", "sys/bus/u4b/usb_process.c:364-393" ], "poc_changes": "No seed PoC existed; authored from scratch (DF-5447 production-include + DF-5496 usb_process rig). Bring-up fixes: (1) header comment contained ttyU*/cuaU* whose */ terminated the comment block -> parser cascade; (2) usbd_do_request_proc prototype already exists in usbdi_util.h:42 (visible via ubser.c:88) -- a manual pre-declaration is unnecessary and trips -Wredundant-decls; (3) pacing: UNPACED SBRK/CBRK bursts coalesce in the usb_proc double buffer -- pairs must be spaced >= request time (1.1 s) for the sustained-loop unbounded-occupancy claim.", "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": 900, "guest_dirty": 0, "build_cmd": "sh /root/df5515/src/build.sh (in-tree kmod at /usr/src/sys/bus/u4b/serial/ub5515, -Werror clean; see build.sh)", "run_cmd": "sh /root/df5515/src/run.sh (kldload /root/df5515/ub5515stall.ko; kldunload; dmesg | grep UB5515)", "code_hash": "12fc847470a98df3e86b12c96c19f7b5737a5d1844f442e36ca45e2a503821e8", "notes": "Guest left pristine (ubser.c md5 85afa08f... restored, harness dirs removed, modules unloaded). Severity Low per family calibration: single 1 s request, TIOCSBRK-gated, availability-only impact.", "recommended_fix": "Bound the cfg-path request timeout: 1000 -> 250 ms at ubser.c:481 (full diff in fix.diff; validated: 914 ms -> 91 ms).", "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 @477); same production-code harness rebuilt -Werror-clean and re-run: phase A closer ELAPSED 91 ms vs 914 ms baseline -- the stall is gone and the break request still completes for a live device in <250 ms. git apply --check passes on the audited repo; guest tree restored and md5-verified after validation.", "fix_evidence": "fix.diff; fix_build.log (RC=0 link line); run.fixed.log (UB5515[A]: closer: unblocked ELAPSED=91 ms); VERDICT.md Fix validation section" } |