⬢ DragonFlyBSD Kernel Audit
DF-4977 / fix.diff
← back to finding ↓ download raw
--- a/sys/dev/pccard/cardbus/cardbus.c	2026-09-25 14:18:13.549631345 +0000
+++ b/sys/dev/pccard/cardbus/cardbus.c	2026-09-25 14:18:13.573631032 +0000
@@ -224,6 +224,7 @@
 	device_t *devlist;
 	int tmp;
 	int err = 0;
+	int error;
 
 	if (device_get_children(cbdev, &devlist, &numdevs) != 0)
 		return (ENOENT);
@@ -239,10 +240,30 @@
 
 		if (dinfo->pci.cfg.dev != devlist[tmp])
 			device_printf(cbdev, "devinfo dev mismatch\n");
-		if (status == DS_ATTACHED || status == DS_BUSY)
-			device_detach(devlist[tmp]);
+		if (status == DS_ATTACHED || status == DS_BUSY) {
+			error = device_detach(devlist[tmp]);
+			if (error != 0) {
+				/*
+				 * Child refuses to go away: keep both the
+				 * child and its dinfo alive, else we free the
+				 * ivars of a live device (UAF) and rip its
+				 * resources out from under the driver.
+				 */
+				device_printf(cbdev,
+				    "%s: child %s failed to detach (%d), "
+				    "keeping its resources\n", __func__,
+				    device_get_nameunit(devlist[tmp]), error);
+				err = error;
+				continue;
+			}
+		}
 		cardbus_release_all_resources(cbdev, dinfo);
-		device_delete_child(cbdev, devlist[tmp]);
+		error = device_delete_child(cbdev, devlist[tmp]);
+		if (error != 0) {
+			/* child still exists and owns dinfo as its ivars */
+			err = error;
+			continue;
+		}
 		pci_freecfg((struct pci_devinfo *)dinfo);
 	}
 	POWER_DISABLE_SOCKET(device_get_parent(cbdev), cbdev);