{
  "finding_id": "DF-2353",
  "status": "reproduced",
  "verdict": "REPRODUCED \u2014 use-after-free read of freed kernel memory, raced by an UNPRIVILEGED user against the actual production uvc_drv_detach() function. The rig registered /dev/videoN nodes via production uvc_v4l2_reg (0666) with a ~65KB data->fmt allocation, ran reg/detach cycles calling the in-tree uvc_drv_detach() through a fabricated device_t, while uid-1001 hammered VIDIOC_ENUM_FMT/ENUM_FRAMESIZES. Result (both with the production function, action 2353prod, and with the verbatim inline call sequence, action 2353): Fatal trap 12, fault virtual address 0xfffff801186d0010 = supervisor read, page not present, stopped at uvc_drv_enum_v4l2_fmt+0x32: testb $0x1,0x10(%r12) \u2014 the fmt->flags read (uvc_drv.c:831) on data->fmt freed by uvc_drv_destroy_data() (uvc_drv.c:2506) while the cdev still dispatched ioctls because destroy_dev() is asynchronous (kern_conf.c:346 -> devfs_core.c:757-763) and ran only later at uvc_drv.c:2511. Panicked in the FIRST detach cycle both runs. FIX VALIDATED: reordered detach (unreg + users drain before any free) survived 3000 production-detach cycles against 18024 unprivileged ioctl iterations with zero faults and zero freed-memory disclosures.",
  "reproduced": true,
  "impact": "panic",
  "confidence": "certain",
  "exploit_chain": "Unplug (or USB unbind) of a UVC camera while a local user hammers ioctls on /dev/videoN: uvc_drv_detach frees data->fmt/data/video BEFORE the async destroy_dev stops dispatch; lockless handlers (uvc_drv_enum_v4l2_fmt uvc_drv.c:826-833 strlcpys fmt->name back to userspace) then read freed slab memory. Demonstrated primitive: freed-memory read -> page-fault panic when the freed pages are unmapped (large fmt); when reused, up to 32 bytes of reallocated kernel heap are disclosed per ENUM_FMT (info-leak oracle). Secondary: uvc_v4l2_open increments v->users on the freed video (a narrow UAF write of +1 on freed memory during the async window). Read/disclosure-focused; no strong write primitive identified via these handlers, so uid0 escalation was not pursued beyond characterization.",
  "evidence": "panic.prod.txt (production uvc_drv_detach variant): Fatal trap 12 ... fault virtual address = 0xfffff801186d0010 ... supervisor read data, page not present Stopped at uvc_drv_enum_v4l2_fmt+0x32: testb $0x1,0x10(%r12); panic.txt (inline verbatim-sequence variant): identical signature at 0xfffff8011878a010. fix_run.log: RIG2353p: finished 3000 cycles, no kernel-side fault + hammer summary done: 18024 iterations, 18023 ENUM_FMT ok, 0 odd descriptions.",
  "kernel_refs": [
    "sys/bus/u4b/uvc/uvc_drv.c:2503",
    "sys/bus/u4b/uvc/uvc_drv.c:2506",
    "sys/bus/u4b/uvc/uvc_drv.c:2511",
    "sys/bus/u4b/uvc/uvc_drv.c:2513",
    "sys/bus/u4b/uvc/uvc_drv.c:826",
    "sys/bus/u4b/uvc/uvc_drv.c:831",
    "sys/bus/u4b/uvc/uvc_v4l2.c:548",
    "sys/bus/u4b/uvc/uvc_v4l2.c:783",
    "sys/kern/kern_conf.c:346",
    "sys/vfs/devfs/devfs_core.c:757"
  ],
  "poc_changes": "No PoC seed existed. Built from scratch: trigger_race.c (unprivileged hammer; note its v4l2_frmsizeenum union padding made VIDIOC_ENUM_FRAMESIZESs cmd number mismatch the kernels \u2014 cosmetic ENOTTY console noise; VIDIOC_ENUM_FMT, the handler that faulted, matched exactly; source kept as-built so hashes match the logs). Rig variants: 2353 (inline verbatim detach sequence) and 2353prod (actual production uvc_drv_detach via fabricated device_t.softc). Crafted device sizes data->fmt at ~65KB so kfree returns pages and the post-free read faults.",
  "attempts": 2,
  "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": "./build.sh  (setup.sh: uvc_rig.ko via make in guest rig dir; cc -O2 -o /tmp/trigger_race trigger_race.c)",
  "run_cmd": "kldload uvc_rig.ko; run_user (nohup /tmp/trigger_race 240 &); sysctl hw.usb.uvcrig=\"2353prod 2000\"   -> panic (see run.sh)",
  "code_hash": "e5589d9d0c28c7c05a941fb3b6220a81993b9bec9724586f83145445a6414ca7",
  "notes": "Evidence class: production-handler KLD dispatch \u2014 teardown is the in-tree uvc_drv_detach function; ioctls are the in-tree dev_ops; only the USB hardware layer is synthesized. Baseline panicked within the first detach cycle (window extends across the asynchronous destroy_dev, not just the five production calls). Guest left up and clean (reset with-src, rig dir removed, module unloaded). Residual hardening note for upstream: an ioctl already in flight when its fds dtor drops users to 0 is not reference-counted; a synchronous devfs drain or per-call refs would close it fully.",
  "recommended_fix": "Reorder uvc_drv_detach: uvc_v4l2_unreg (async destroy_dev) first, drain video->users to 0 before freeing video/data/ctrl",
  "fix_status": "fixed",
  "fix_baseline_reproduced": 1,
  "fix_patched_reproduced": 0,
  "fix_verdict": "With fix.diff applied (guest /usr/src, module rebuilt -Werror clean): 3000 reg/detach cycles driving the patched production uvc_drv_detach raced by the same unprivileged hammer (18024 iterations, 18023 successful ENUM_FMT, 0 odd descriptions) \u2014 no fault, guest up, nodes cleanly removed. Baseline panicked in cycle 1; patched survived 3000 cycles.",
  "fix_evidence": "fix_run.log: RIG2353p: cycle 2900/3000 done ... RIG2353p: finished 3000 cycles, no kernel-side fault; hammer log: trigger_race: done: 18024 iterations, 18023 ENUM_FMT ok, 0 odd descriptions; fix_build.log: clean patched build."
}