⬢ DragonFlyBSD Kernel Audit
DF-5394 / fix.diff
← back to finding ↓ download raw
--- a/sys/bus/u4b/controller/usb_controller.c
+++ b/sys/bus/u4b/controller/usb_controller.c
@@ -196,8 +196,6 @@
 		/* was never setup properly */
 		return (0);
 	}
-	/* Stop power watchdog */
-	usb_callout_drain(&bus->power_wdog);
 
 #if USB_HAVE_ROOT_MOUNT_HOLD
 	/* Let the USB explore process detach all devices. */
@@ -221,6 +219,15 @@
 #endif
 	USB_BUS_UNLOCK(bus);
 
+	/*
+	 * Stop power watchdog.  Must happen after the detach job above:
+	 * usb_bus_attach() arms this callout as its last action and the
+	 * detach job is queued behind the attach job in the explore
+	 * process, so draining here always observes the armed callout,
+	 * while draining before the jobs (as before) raced the arming.
+	 */
+	usb_callout_drain(&bus->power_wdog);
+
 #if USB_HAVE_PER_BUS_PROCESS
 	/* Get rid of USB callback processes */
 
@@ -895,6 +902,18 @@
 	} else
 #endif
 	{
+		/*
+		 * Set the softc synchronously, BEFORE signalling the
+		 * asynchronous usb_bus_attach() job, so that a racing
+		 * usb_detach() always observes a non-NULL softc and
+		 * performs the full teardown dance instead of silently
+		 * skipping it while the explore process is still running.
+		 * usb_bus_attach()/usb_bus_detach() set/clear it again;
+		 * device_set_softc() sees DF_EXTERNALSOFTC and will not
+		 * free the pointer.
+		 */
+		device_set_softc(dev, bus);
+
 		/* Get final attach going */
 		USB_BUS_LOCK(bus);
 		usb_proc_msignal(USB_BUS_EXPLORE_PROC(bus),