⬢ DragonFlyBSD Kernel Audit
DF-5002 / fix.diff
← back to finding ↓ download raw
--- a/sys/dev/netif/mii_layer/mii.c	2026-09-25 18:16:01.683350318 +0000
+++ b/sys/dev/netif/mii_layer/mii.c	2026-09-25 18:24:35.396634613 +0000
@@ -188,12 +188,31 @@
 miibus_detach(device_t dev)
 {
 	struct mii_data *mii;
+	device_t *children;
+	int count, i;
 
+	/*
+	 * DF-5002: newbus never frees device ivars (subr_bus.c
+	 * device_delete_child drops the pointer); the per-PHY
+	 * mii_attach_args we kmalloc'ed in miibus_probe() are ours to
+	 * release while the children are still enumerated.
+	 */
+	if (device_get_children(dev, &children, &count) == 0) {
+		for (i = 0; i < count; i++) {
+			kfree(device_get_ivars(children[i]), M_DEVBUF);
+			device_set_ivars(children[i], NULL);
+		}
+		kfree(children, M_TEMP);
+	}
 	bus_generic_detach(dev);
 	mii = device_get_softc(dev);
 	ifmedia_removeall(&mii->mii_media);
 	mii->mii_ifp = NULL;
 
+	/* ... and the mii_probe_args we attached to the bus itself. */
+	kfree(device_get_ivars(dev), M_DEVBUF);
+	device_set_ivars(dev, NULL);
+
 	return 0;
 }
 
@@ -272,6 +291,14 @@
 	}
 
 	if (i == MII_NPHY) {
+		/*
+		 * DF-5002: the child is deleted unattached; newbus does not
+		 * free ivars, so release our mii_probe_args here instead of
+		 * leaking them on every failed probe (bge retries this path
+		 * up to 5 times per attach, if_bge.c).
+		 */
+		kfree(args, M_DEVBUF);
+		device_set_ivars(*child, NULL);
 		device_delete_child(dev, *child);
 		*child = NULL;
 		return ENXIO;