# DF-5790 VERDICT — REPRODUCED (unbounded M_BUS leak per probed-then-deleted device)

## Mechanism (line-accurate)

1. `device_set_driver(child, drv)` during probe allocates the softc —
   `sys/kern/subr_bus.c:1952-1954` (`dev->softc = kmalloc(driver->size,
   M_BUS, M_INTWAIT | M_ZERO)`); `device_probe_child()` leaves the child
   in `DS_ALIVE` with driver+softc bound (`sys/kern/subr_bus.c:1486`).
2. `device_delete_child(parent, child)` → `device_detach(child)` →
   **short-circuit** `if (dev->state != DS_ATTACHED) return(0);`
   (`sys/kern/subr_bus.c:2136-2137`) — the teardown block at 2146-2151
   (which contains the only subr_bus `device_set_driver(dev, NULL)`) is
   skipped.
3. `kobj_delete((kobj_t)child, M_BUS)` (`sys/kern/subr_bus.c:1306`) →
   `sys/kern/subr_kobj.c:264-273` — frees the device object only; the
   softc is orphaned → leak of `driver->size` bytes per cycle.

## Baseline result (stock kernel #0) — reproduced

`run.log`: with driver softc size 8192 —

| stage | M_BUS MemUse |
|---|---|
| baseline | 97.6K |
| 100 control add/delete cycles (no probe) | 97.7K |
| 100 add/**probe**/delete cycles | **898K** (+~800K = 100×8192) |
| 100 more | **1.66M** |
| after `kldunload rig` | **1.66M (permanent)** |

kernel log: `DF5790: ... last child state=1 softc=0xfffff801186b4000
(LEAKED, never kfree'd)` — the deleted child was DS_ALIVE with a live
softc pointer.

Control run isolates the cause precisely: without the probe (no softc)
the identical churn grows M_BUS by ~0.1K total.

## Impact

Unbounded kernel heap leak (`M_BUS`), permanent for the uptime.  In-tree
reachability today is narrow (USB temp_dev deletes between probe and
attach; async-attach window; any third-party/newbus driver deleting
children in the probed state), so rated Low — but the protocol flaw is
certain: the delete path simply does not own the softc.

## Fix validation — FIXED

`fix.diff`: in `device_delete_child()`, after `device_detach(child)`
succeeds, add

```c
	if (child->driver != NULL)
		device_set_driver(child, NULL);
```

which releases the driver binding and frees the softc before the object
is destroyed.  Patched kernel #1 (Oct 12 18:33:11): the identical
200-cycle run shows **97.7K → 97.7K → 97.7K** (`fixrun.log`) — zero
growth; the "LEAKED" path is gone (kernel still prints the state=1
softc pointer before delete, but the memory is now reclaimed).

## Guest

Same rig/kernel builds as DF-5789; guest reset to clean-source snapshot
afterwards.

## Fix status (batch validation)
Applied with the 36 sibling fix.diffs of this batch in findings/poc/_batch41/all_fixes.patch; single in-guest `make -j6 nativekernel KERNCONF=X86_64_GENERIC` completed RC=0 with zero errors under -Werror (full log: findings/poc/_batch41/fix_build8.log). Behavior A/B intentionally skipped for this Info-tier item.
