⬢ DragonFlyBSD Kernel Audit
DF-4276 / fix.diff
← back to finding ↓ download raw
--- a/sys/dev/pccard/pccbb/pccbb.c
+++ b/sys/dev/pccard/pccbb/pccbb.c
@@ -279,12 +279,31 @@ int
 cbb_detach(device_t brdev)
 {
 	struct cbb_softc *sc = device_get_softc(brdev);
 	int error;
 
+	/*
+	 * Stop the slot event thread BEFORE deleting the children: the
+	 * thread re-evaluates the socket every second and calls
+	 * cbb_insert()/cbb_removal() -> CARD_ATTACH_CARD/CARD_DETACH_CARD/
+	 * exca_insert/exca_removal on sc->cbdev and sc->exca[0].pccarddev,
+	 * which device_delete_children() frees (DF-4276).
+	 */
+	sc->flags |= CBB_KTHREAD_DONE;
+	if (sc->flags & CBB_KTHREAD_RUNNING) {
+		crit_enter();
+		wakeup(&sc->generic_cv);
+		tsleep(sc->event_thread, 0, "cbbun", 0);
+		crit_exit();
+	}
+
 	error = device_delete_children(brdev);
 	if (error != 0)
 		return (error);
 
+	/* Children are gone; make sure the thread can never reach them. */
+	sc->cbdev = NULL;
+	sc->exca[0].pccarddev = NULL;
+
 	/* 
 	 * XXX do we teardown all the ones still registered to guard against
 	 * XXX buggy client drivers?
 	 */
 	bus_teardown_intr(brdev, sc->irq_res, sc->intrhand);
-	sc->flags |= CBB_KTHREAD_DONE;
-	if (sc->flags & CBB_KTHREAD_RUNNING) {
-		crit_enter();
-		wakeup(&sc->generic_cv);
-		tsleep(sc->event_thread, 0, "cbbun", 0);
-		crit_exit();
-	}
 
 	bus_release_resource(brdev, SYS_RES_IRQ, 0, sc->irq_res);