⬢ DragonFlyBSD Kernel Audit
DF-5407 / verdict.json
← back to finding ↓ download raw
{
  "finding_id": "DF-5407",
  "status": "reproduced",
  "reproduced": true,
  "impact": "dos",
  "confidence": "certain",
  "verdict": "REPRODUCED with the production code verbatim: uplcom_attach() chains 14 sequential synchronous EP0 control requests (1x uplcom_reset at uplcom.c:412 + 13x uplcom_pl2303_init at uplcom.c:433/497-525), each at the 5000 ms USB_DEFAULT_TIMEOUT (usbdi.h:87,511-512). USB allows a device to NAK a control data/status stage arbitrarily long; the hosts only bound is that timeout, enforced while the requester sleeps uninterruptibly (usb_request.c:633-636,700-708). The harness awk-extracted the three production functions UNMODIFIED from the guests clean /usr/src snapshot and ran them against an evil-device model answering every request successfully at just-under-timeout: the attach chain pinned the calling thread for 67337/67320/67337/67369 ms across 4 executions (deterministic 14x4900 ms), with kldload(2) itself blocked uninterruptibly for the whole window; the request trace matches the documented PL2303HX sequence exactly (14 requests, incl. 2/0x44 at uplcom.c:515). At real attach time this chain runs on the per-bus USB explore thread (uhub_explore_sub usb_hub.c:530/1103 -> usb_probe_and_attach usb_device.c:1316-1406 under the enum lock), so one evil adapter freezes hotplug AND unplug processing for every device on the bus for ~67 s per insertion, repeatable by a self-re-enumerating gadget. Not memory corruption: every requests wLength <= 1 <= sizeof(buf[4]) (0 overruns counted). Honest boundary: the explore-thread context is source-cited (same citations accepted for DF-5359/5367/5383), not hardware-executed; no QEMU USB model can present a PL2303 VID:PID (emulated usb-serial is 0525:7701 -> uftdi), hence the prescribed KLD-harness-with-production-code class.",
  "exploit_chain": "physical/evil-adapter: (1) scriptable USB device (Facedacer/gadget) presents a VID:PID from uplcom_devs[] (e.g. 067b:2303, uplcom.c:271) with device descriptor bDeviceClass!=0x02 and bMaxPacketSize==0x40 -> TYPE_PL2303HX (uplcom.c:360-366); (2) its EP0 answers each of the 14 vendor requests successfully after ~4.9 s of NAK (USB-legal); (3) the per-bus explore thread stays inside uplcom_attach for ~67 s, freezing enumeration and unplug handling bus-wide; (4) the gadget electrically re-enumerates itself and repeats -> near-continuous USB enumeration DoS. No privilege-escalation component exists in this bug class (bounded DoS only).",
  "evidence": "run.log + run.2.log: HX5407[A]: uplcom_attach chain DONE: 67337/67320/67337/67369 ms pinned, 14 sync EP0 requests and [B]: 2170/2204/2183 ms (fix mechanism); full 14-request EP0 trace with type/req/val/idx/len per request (wLength<=1, 0 overruns); build.log: verbatim-extraction sha256s + -Werror kmod build; fix_compile.log: whole fix.diffd file compiles clean as uplcomfix5407.ko; VERDICT.md: full narrative + negative-results sweep",
  "kernel_refs": [
    "sys/bus/u4b/serial/uplcom.c:404-436",
    "sys/bus/u4b/serial/uplcom.c:460-473",
    "sys/bus/u4b/serial/uplcom.c:475-495",
    "sys/bus/u4b/serial/uplcom.c:497-525",
    "sys/bus/u4b/serial/uplcom.c:502-511",
    "sys/bus/u4b/usbdi.h:87",
    "sys/bus/u4b/usbdi.h:511-512",
    "sys/bus/u4b/usb_request.c:424-430",
    "sys/bus/u4b/usb_request.c:633-636",
    "sys/bus/u4b/usb_request.c:700-708",
    "sys/bus/u4b/usb_device.c:1316-1406",
    "sys/bus/u4b/usb_hub.c:530",
    "sys/bus/u4b/usb_hub.c:1103"
  ],
  "poc_changes": "no seeded PoC existed (pass-2 finding, first evidence pack); built from scratch: KLD harness that awk-extracts the production uplcom_reset/uplcom_pl2303_do/uplcom_pl2303_init VERBATIM from the guests clean /usr/src snapshot (with the static usb_error_t/static int return-type lines via look-behind) and re-targets only usbd_do_request()/usbd_do_request_flags() to an evil-device model (successful answer at timeout-100 ms, uninterruptible WXFER-mirroring sleep). Build iterations fixed: missing module-dir mkdir, usb_process.h include order (needs sys/condvar.h), awk -v regex mangling (switched to index()), return-type line extraction, and UPLCOM_INIT_TIMEOUT extraction from the fixed copy.",
  "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": 480,
  "guest_dirty": 0,
  "build_cmd": "sh /root/df5407/build.sh  (in-tree kmod build at /usr/src/sys/bus/u4b/serial/hx5407: verbatim production extraction -> uplcomstall.ko; patch -p1 of fix.diff onto a scratch copy -> phase-B extraction; full-file -Werror compile of the patched file -> uplcomfix5407.ko)",
  "run_cmd": "sh /root/df5407/run.sh  (kldload /root/df5407/uplcomstall.ko; kldunload uplcomstall; dmesg | grep HX5407)",
  "code_hash": "d186bb71a982ca259035576291fdfb55ca1526198d2859ee4dc74dc551ce8617",
  "notes": "Family calibration: DF-5359 (uipaq 12.8 s) = Low, DF-5382 (umcs continuous) = Medium; this is ~67 s/insertion (5x uipaq), self-re-enumerating to near-continuous, with unplug processing frozen too -> Medium. Same code shape exists in FreeBSDs uplcom (upstream candidate). Negative results (all killed, path:line in VERDICT.md): buf[4] OOB (wLength<=1 at all sites, usb_request.c:566-614 bounds data stage), buf[9] intr copy (actlen>=9 guard, bufsize=0 -> max_frame_size, usb_transfer.c:646-653), bulk bufs fixed 1024=bufsize, attach-error double-detach safe (usb_serial.c:371-372), device data never sizes a copy (chiptype/data_iface_no/sc_msr all constant-or-masked), negative c_ospeed on HX is a hardening nit only (4-byte USETDW store), cfg callbacks serialized on sc_tq under sc_lock, init-after-ucom_attach drain window is DF-5320-family core behavior.",
  "recommended_fix": "Bound the 14 attach-path control requests to 250 ms each (UPLCOM_INIT_TIMEOUT passed via usbd_do_request_flags in uplcom_reset/uplcom_pl2303_do) instead of the 5000 ms USB_DEFAULT_TIMEOUT, capping the whole attach chain at 3.5 s worst-case (fix.diff, mechanism identical to DF-5382/5383s umcs fix)",
  "fix_status": "fixed",
  "fix_baseline_reproduced": 1,
  "fix_patched_reproduced": 1,
  "fix_verdict": "fix.diff is git-apply-able against the pristine tree (git apply --check on host; patch -p1 on the guests clean /usr/src copy, 5 hunks OK in build.log); the WHOLE patched file compiles -Werror-clean as a kmod (uplcomfix5407.ko, fix_compile.log/fix_build.log); harness phase B executes the production functions extracted from the PATCHED file and measures 67.3 s -> 2.2 s (31x reduction of the stall ceiling, deterministic 14x150 ms). Scope caveat: mechanism + compile level; end-to-end with a physical crafted PL2303 device is not possible on this guest; no full kernel rebuild (DoS-class finding, not memory corruption).",
  "fix_evidence": "fix.diff (sha256 5c62598ea2962ab96b2e602c452e91c1e9526e009359b8a30030d681a5117b4d); fix_compile.log/fix_build.log (uplcomfix5407.ko, -Werror clean); fix_run.log + run.log HX5407[B]: uplcom_attach chain DONE: 2170/2204/2183 ms vs [A]: 67337/67320/67337/67369 ms; VERDICT.md Fix validation section"
}