⬢ DragonFlyBSD Kernel Audit
DF-4996 / fix.diff
← back to finding ↓ download raw
--- sys/dev/netif/ral/if_ral_pci.c
+++ sys/dev/netif/ral/if_ral_pci.c
@@ -272,17 +272,31 @@ ral_pci_attach(device_t dev)
 		device_printf(dev, "could not allocate interrupt resource\n");
 		pci_release_msi(dev);
 		bus_release_resource(dev, SYS_RES_MEMORY,
 		    rman_get_rid(psc->mem), psc->mem);
 		return ENXIO;
 	}
 
 	error = (*psc->sc_opns->attach)(dev, pci_get_device(dev));
 	if (error != 0) {
-		(void)ral_pci_detach(dev);
+		/*
+		 * The child attach failed and has already unwound all of
+		 * its own state (DMA rings freed, driver lock destroyed);
+		 * in particular ieee80211_ifattach() was never called.
+		 * Only release the PCI-layer resources here: running the
+		 * full ral_pci_detach() would dispatch the child detach a
+		 * SECOND time and ieee80211_ifdetach() would LIST_REMOVE()
+		 * an ieee80211com that was never attached (NULL-pointer
+		 * write in sys/sys/queue.h LIST_REMOVE -> panic), followed
+		 * by double-frees of every DMA ring.
+		 *
+		 * The IRQ resource must be released before pci_release_msi()
+		 * (pci_release_msi_method() returns EBUSY while an MSI
+		 * resource is still allocated).
+		 */
+		bus_release_resource(dev, SYS_RES_IRQ,
+		    rman_get_rid(psc->irq), psc->irq);
+		pci_release_msi(dev);
+		bus_release_resource(dev, SYS_RES_MEMORY,
+		    rman_get_rid(psc->mem), psc->mem);
 		return error;
 	}
 
 	/*
 	 * Hook our interrupt after all initialization is complete.
 	 */