⬢ DragonFlyBSD Kernel Audit
DF-4725 / fix.diff
← back to finding ↓ download raw
--- a/sys/dev/sound/pci/aureal.c
+++ b/sys/dev/sound/pci/aureal.c
@@ -596,7 +596,7 @@ au_pci_attach(device_t dev)
 #endif
 		if (reg[j]) {
 			au->st[i] = rman_get_bustag(reg[j]);
 			au->sh[i] = rman_get_bushandle(reg[j]);
 			mapped++;
 		}
@@ -604,7 +604,7 @@ au_pci_attach(device_t dev)
 #endif
-		if (mapped) j++;
+		if (reg[j]) j++;	/* only count mapped BARs so bad: never
+					   sees a NULL reg[i] (DF-4725) */
 		if (j == 10) {
 			/* XXX */
 			device_printf(dev, "too many resources");
 			goto bad;
 		}
@@ -655,14 +655,19 @@ au_pci_attach(device_t dev)
 	return 0;
 
  bad:
-	if (au) free(au, M_DEVBUF);
+	/*
+	 * Unwind in dependency order (DF-4725): the IRQ handler still
+	 * references `au`, so it must be torn down BEFORE au is freed;
+	 * skip reg[] slots that never mapped; free au LAST.
+	 */
+	if (ih) bus_teardown_intr(dev, irq, ih);
+	if (irq) bus_release_resource(dev, SYS_RES_IRQ, irqid, irq);
 	for (i = 0; i < j; i++)
-		bus_release_resource(dev, type[i], regid[i], reg[i]);
-	if (ih) bus_teardown_intr(dev, irq, ih);
-	if (irq) bus_release_resource(dev, SYS_RES_IRQ, irqid, irq);
+		if (reg[i] != NULL)
+			bus_release_resource(dev, type[i], regid[i], reg[i]);
+	if (au) free(au, M_DEVBUF);
 	return ENXIO;
 }