DF-5041 / fix.diff
--- 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", |