⬢ DragonFlyBSD Kernel Audit
DF-5041 / fix.diff
← back to finding ↓ download raw
--- a/sys/dev/acpica/acpi_pcib.c
+++ b/sys/dev/acpica/acpi_pcib.c
@@ -114,6 +114,15 @@
     if (child == NULL)
 	return;
 
+    /*
+     * Only a PCI interrupt link device may be referenced by a _PRT
+     * Source.  Force-attach the named device (legitimate link devices
+     * are attached here), then verify the pci_link driver actually
+     * claimed it.  A buggy or hostile _PRT can name any namespace
+     * device, including devices run by unrelated drivers; feeding
+     * those into the pci_link code type-confuses their softc with
+     * struct acpi_pci_link_softc and follows wild pointers.
+     */
     /* If the device hasn't been probed yet, force it to do so. */
     error = device_probe_and_attach(child);
     if (error != 0) {
@@ -122,6 +131,13 @@
 	return;
     }
 
+    /* Reject devices that were attached by some other driver. */
+    if (device_get_devclass(child) != devclass_find("pci_link")) {
+	device_printf(pcib, "PRT source %s is not a PCI interrupt link\n",
+	    entry->Source);
+	return;
+    }
+
     /* Add a reference for a specific bus/device/pin tuple. */
     acpi_pci_link_add_reference(child, entry->SourceIndex, pcib,
 	ACPI_ADR_PCI_SLOT(entry->Address), entry->Pin);
@@ -210,6 +226,7 @@
     ACPI_PCI_ROUTING_TABLE *prt;
     struct prt_lookup_request pr;
     ACPI_HANDLE lnkdev;
+    device_t lnkchild;
     int interrupt;
 
     ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
@@ -282,8 +299,15 @@
 	    prt->Source);
 	goto out;
     }
-    interrupt = acpi_pci_link_route_interrupt(acpi_get_device(lnkdev),
-	prt->SourceIndex);
+    /* The source must be an attached PCI interrupt link device. */
+    lnkchild = acpi_get_device(lnkdev);
+    if (lnkchild == NULL ||
+	device_get_devclass(lnkchild) != devclass_find("pci_link")) {
+	device_printf(pcib, "PRT source %s is not an attached PCI interrupt "
+	    "link device\n", prt->Source);
+	goto out;
+    }
+    interrupt = acpi_pci_link_route_interrupt(lnkchild, prt->SourceIndex);
 
     if (bootverbose && PCI_INTERRUPT_VALID(interrupt)) {
 	device_printf(pcib, "slot %d INT%c routed to irq %d via %s\n",