⬢ DragonFlyBSD Kernel Audit
DF-5315 / verdict.json
← back to finding ↓ download raw
{
  "finding_id": "DF-5315",
  "status": "reproduced",
  "verdict": "Unprivileged USB_FS_OPEN x USB_FS_OPEN on one ugen fd slot double-enters usbd_transfer_setup() (unlocked EBUSY check at usb_generic.c:1462; setup NULLs its slot at entry, usb_transfer.c:935, sleeps on enum lock + kmalloc, stores the pointer only at :1138). Every barrier-synchronised round double-won: 121 opens -> 61 orphaned usb_xfer root blocks (~1 MB M_USB leaked in 20 s, permanent) and endpoint->refcount_alloc pinned at USB_EP_REF_MAX=0x3F, so after full cleanup (CLOSE+UNINIT+re-INIT) USB_FS_OPEN fails ENOMEM forever -- the control endpoint is dead for ugen ioctls, read()/write() and kernel drivers until replug/reboot. Distinct from DF-5287 (read()/write() path on f->xfer[]): this is the ioctl path on f->fs_xfer[], and the DF-5287/5288 fixes do not cover it.",
  "reproduced": true,
  "impact": "dos",
  "confidence": "certain",
  "exploit_chain": "unpriv maxx -> shared O_RDWR fd on /dev/usb/0.2.0 -> FS_INIT -> two threads barrier-fire USB_FS_OPEN(ep0) -> both pass the unlocked slot check -> both run sleeping setups -> second entry NULLs/overwrites firsts slot pointer -> orphaned xfer keeps endpoint->refcount_alloc and its ~17 KB root block -> repeat 61x -> endpoint permanently rejects all setups (ENOMEM) + unbounded kernel memory leak per endpoint/device replugged. No memory-corruption face: the orphan is never freed nor reused, only leaked.",
  "evidence": "run.log (baseline: counters freeze 60+61, POST-CLEANUP FAILED ENOMEM, vmstat 16/19.8K -> 331/1.02M), run.patched.log (600 serialised opens, POST-CLEANUP SUCCEEDED, zero orphan growth)",
  "kernel_refs": [
    "sys/bus/u4b/usb_generic.c:1456-1465",
    "sys/bus/u4b/usb_generic.c:1538-1540",
    "sys/bus/u4b/usb_transfer.c:935",
    "sys/bus/u4b/usb_transfer.c:942",
    "sys/bus/u4b/usb_transfer.c:1118-1121",
    "sys/bus/u4b/usb_transfer.c:1138",
    "sys/bus/u4b/usb_transfer.c:1220"
  ],
  "poc_changes": "Seed sketched from the DF-5287 rig (same device, barrier-synced double-entry, refcount-exhaustion probe). Fixed two harness bugs found during verification: (1) probe-open left the slot occupied -> next round armed EBUSY (now closes the probe); (2) shutdown barrier had main participating in a racer-only 2-barrier -> deadlock (main now signals stop via flag only).",
  "attempts": 4,
  "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": 400,
  "guest_dirty": 1,
  "build_cmd": "cc -O -Wall -o df5315 df5315.c -pthread -include stdlib.h",
  "run_cmd": "./df5315 20   (unprivileged maxx, /dev/usb/0.2.0 chmod 0666)",
  "code_hash": "a4e039aa067acf46045ce3e467b6a8b4f4b94669ba137ea5eec1cf077239267d",
  "notes": "Race won essentially every round (setup window is ~200 ms). An exploratory run on an earlier boot reproduced the identical signature. The orphaned blocks are only visible via vmstat -m (M_USB) -- no other userland observable.",
  "recommended_fix": "Claim the fs_xfer slot under priv_lock with a sentinel before entering usbd_transfer_setup(), run the setup into a local pointer, publish/clear under the lock (DF-5314/fix.diff USB_FS_OPEN hunk)",
  "fix_status": "fixed",
  "fix_baseline_reproduced": 1,
  "fix_patched_reproduced": 0,
  "fix_verdict": "DF-5314/fix.diff (which carries the USB_FS_OPEN setup-claim) built and booted: opens serialise (600 successes/12 s), no refcount exhaustion, POST-CLEANUP OPEN SUCCEEDED, vmstat -m USB shows zero orphan growth after the full validation suite (baseline: 61 orphans + permanent ENOMEM).",
  "fix_evidence": "run.patched.log, ../DF-5314/fix_build.log, ../DF-5314/run.patched.log"
}