{
  "finding_id": "DF-5790",
  "status": "reproduced",
  "verdict": "device_delete_child() (sys/kern/subr_bus.c:1283-1310) destroys a probed-but-unattached (DS_ALIVE) child without freeing its softc: device_detach()s short-circuit at subr_bus.c:2136-2137 returns 0 for state != DS_ATTACHED, skipping the only teardown that calls device_set_driver(dev,NULL) (subr_bus.c:2150), so the softc kmallocd during probe (subr_bus.c:1952-1954) is orphaned when kobj_delete(child) (subr_bus.c:1306, subr_kobj.c:264-273) frees the device object. Verified live on stock kernel: 100 add/probe/delete cycles with an 8192-byte softc grow M_BUS by ~800K (97.7K -> 898K -> 1.66M after 200), permanent across kldunload; control cycles without the probe grow 0.1K. Kernel log proves the deleted child was state=1 (DS_ALIVE) holding a live softc pointer.",
  "reproduced": true,
  "impact": "leak",
  "confidence": "certain",
  "exploit_chain": "device_add_child(nexus0, dfleak, -1) -> device_probe_child() binds dfleak driver + allocates 8192-byte softc, child state=DS_ALIVE -> device_delete_child() -> device_detach short-circuit (no set_driver(NULL)) -> kobj_delete frees device struct only -> 8192 bytes of M_BUS leaked per cycle, unbounded, permanent for uptime",
  "evidence": "run.log (vmstat -m bus 97.6K -> 898K -> 1.66M, survives kldunload; control +0.1K); dmesg/rig.txt DF5790: 100 add/probe/delete cycles ... last child state=1 softc=0xfffff801186b4000 (LEAKED, never kfreed); fixrun.log (patched kernel: 97.7K -> 97.7K after 200 cycles)",
  "kernel_refs": [
    "sys/kern/subr_bus.c:1306",
    "sys/kern/subr_bus.c:1952",
    "sys/kern/subr_bus.c:2136",
    "sys/kern/subr_bus.c:2150",
    "sys/kern/subr_kobj.c:264",
    "sys/bus/u4b/usb_device.c:1415"
  ],
  "poc_changes": "PoC authored fresh (shared rig with DF-5789); leak sysctl hw.df5789.leak drives device_probe_child() directly (exported at sys/bus.h:389) so the child is caught exactly in DS_ALIVE; hw.df5789.leakctl is the no-probe control isolating the softc as the leaked object",
  "attempts": 3,
  "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": 840,
  "guest_dirty": 0,
  "build_cmd": "cd /root/df5789 && make KERNBUILDDIR=/usr/obj/usr/src/sys/X86_64_GENERIC",
  "run_cmd": "cd /root/df5789 && sh run5790.sh",
  "code_hash": "376cd004b0eed058cce2f3f12a3bf3436ddacfba583102218f7680f222fefc90",
  "notes": "In-tree reachability today is narrow (usb temp_dev delete at usb_device.c:1415 after a probe at :1238 that failed to attach leaves DS_NOTPRESENT with softc already freed; the leak window needs a delete while DS_ALIVE - async-attach mid-window or future/newbus drivers), so severity Low; the protocol flaw itself is certain and the primitive (8KB/cycle unbounded permanent leak) is proven.",
  "recommended_fix": "device_delete_child(): after device_detach(child) succeeds, add if (child->driver != NULL) device_set_driver(child, NULL); before deleting grandchildren/freeing the object; see fix.diff",
  "fix_status": "fixed",
  "fix_baseline_reproduced": true,
  "fix_patched_reproduced": true,
  "fix_verdict": "fix.diff applied in guest /usr/src, quickkernel #1 built+installed+rebooted: identical 200-cycle run shows M_BUS flat at 97.7K (vs +1.56M on stock); the softc is now freed by the added device_set_driver(child,NULL). Leak gone.",
  "fix_evidence": "fixrun.log (97.7K before == after all cycles) vs run.log (97.7K -> 1.66M); kbuild.log/kinstall.log in ../DF-5789/"
}