# DF-5002 — miibus leaks every kmalloc'd device ivars (mii_attach_args /
mii_probe_args); nothing in the kernel ever frees them

## What

`miibus_probe()` kmallocs one `struct mii_attach_args` per probed PHY
address and stores it as the child's newbus **ivars** (mii.c:157-161);
`mii_probe()` kmallocs one `struct mii_probe_args` and stores it as the
miibus device's ivars (mii.c:263-267). Newbus does **not** own or free
device ivars: `device_delete_child()` (sys/kern/subr_bus.c:1284-1310)
frees the device structure only and simply drops the `ivars` pointer
(set to NULL only at creation, subr_bus.c:1216). No code anywhere in
`sys/` kfrees these allocations (verified: the only kfrees in the whole
mii_layer are unrelated `devlist`/M_TEMP frees in tlphy.c:183 and
mlphy.c:218,426).

Leak sites:

1. **Every failed `mii_probe()`** — the ENXIO path (mii.c:274-278)
   deletes the miibus child and drops `args` (~56 bytes). bge retries
   this path up to 5 times per attach (`if_bge.c:2582-2589` "Probe MII
   again" loop) → up to 5 leaks per attach of a bge card with an
   unresponsive PHY.
2. **Every miibus destroy** (NIC detach: module unload, CardBus/USB
   hot-removal — e.g. `if_rue` USB NICs use miibus via ruephy) — leaks
   the miibus's `mii_probe_args` plus one `mii_attach_args` per PHY
   child (~104-152 bytes per detach cycle). USB dongle replug is an
   unprivileged-with-physical-access repeatable trigger.

Pure resource leak (CWE-401): the memory stays allocated forever
(no UAF angle — nothing retains the pointer). Impact is slow kernel
heap exhaustion at ~10^7+ cycles; no confidentiality/integrity impact.

## Status

`untested` dynamically: triggering requires a miibus-attached NIC (none
exists on the QEMU guest — its NICs don't use miibus); the defect is
nevertheless provable by inspection (allocation sites above; absence of
any free verified by grep over sys/; newbus ivars semantics verified in
subr_bus.c). The proposed `fix.diff` compiles clean under the kernel's
full `-Werror` set as a KLD source on the guest (fixcheck-build.log).

## Fix

`fix.diff`: free the per-PHY `mii_attach_args` in `miibus_detach()`
(children are still enumerated there; every NIC driver deletes the
miibus child on detach — verified across if_bge/if_nfe/if_xl/if_vr/...),
free the bus's own `mii_probe_args` at the end of `miibus_detach()`, and
free them on the `mii_probe()` ENXIO path. `device_set_ivars(..., NULL)`
after each kfree to keep any re-probe from reading a dangling pointer.
