⬢ DragonFlyBSD Kernel Audit
DF-5643 / fix.diff
← back to finding ↓ download raw
--- a/sys/bus/smbus/smbus.c
+++ b/sys/bus/smbus/smbus.c
@@ -29,6 +29,7 @@
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/kernel.h>
+#include <sys/malloc.h>
 #include <sys/module.h>
 #include <sys/bus.h> 
 
@@ -89,11 +90,24 @@
 static int
 smbus_attach(device_t dev)
 {
+	device_t *devlist;
+	int nchildren;
 	unsigned char addr;
 
-	device_add_child(dev, NULL, device_get_unit(dev));
-	for (addr = 16; addr < 112; ++addr) {
-		smbus_probe_device(dev, addr);
+	/*
+	 * Children survive driver teardown (devclass_delete_driver only
+	 * detaches them, never deletes; subr_bus.c:888-897), so the bus
+	 * must only be populated on FIRST attach.  Re-creating the child
+	 * set on every attach leaks struct bsd_device per cycle and mints
+	 * duplicate remapped /dev/smbN[-XX] nodes on one physical bus.
+	 */
+	if (device_get_children(dev, &devlist, &nchildren) == 0) {
+		kfree(devlist, M_TEMP);
+		if (nchildren == 0) {
+			device_add_child(dev, NULL, device_get_unit(dev));
+			for (addr = 16; addr < 112; ++addr)
+				smbus_probe_device(dev, addr);
+		}
 	}
 
 	/*bus_generic_probe(dev);*/
@@ -105,8 +119,17 @@
 static int
 smbus_detach(device_t dev)
 {
+	struct smbus_softc *sc = (struct smbus_softc *)device_get_softc(dev);
 	int error;
 
+	/*
+	 * A client that owns the bus (or is parked waiting for it) still
+	 * holds the softc in-flight; a successful detach would free the
+	 * softc underneath it (device_set_driver, subr_bus.c:1941-1946).
+	 */
+	if (sc->owner != NULL)
+		return (EBUSY);
+
 	error = bus_generic_detach(dev);
 	if (error)
 		return (error);