⬢ DragonFlyBSD Kernel Audit
DF-4451 / fix.diff
← back to finding ↓ download raw
--- a/sys/dev/acpica/acpi_pci_link.c
+++ b/sys/dev/acpica/acpi_pci_link.c
@@ -232,6 +232,16 @@
 		break;
 	case ACPI_RESOURCE_TYPE_IRQ:
 	case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
+		if (req->link_index >= req->sc->pl_num_links) {
+			/*
+			 * _CRS returned more IRQ resources than the
+			 * counting walk saw (stateful method).
+			 */
+			device_printf(req->sc->pl_dev,
+			    "_CRS returned more IRQ resources than counted\n");
+			req->res_index++;
+			break;
+		}
 		KASSERT(req->link_index < req->sc->pl_num_links,
 		    ("%s: array boundary violation", __func__));
 		link = &req->sc->pl_links[req->link_index];
@@ -308,6 +318,16 @@
 		if (req->in_dpf == DPF_IGNORE)
 			break;
 
+		if (req->link_index >= req->sc->pl_num_links) {
+			/*
+			 * _PRS returned more IRQ resources than were
+			 * counted (stateful or _CRS/_PRS mismatch).
+			 */
+			device_printf(req->sc->pl_dev,
+			    "_PRS returned more IRQ resources than counted\n");
+			req->res_index++;
+			break;
+		}
 		KASSERT(req->link_index < req->sc->pl_num_links,
 		    ("%s: array boundary violation", __func__));
 		link = &req->sc->pl_links[req->link_index];
@@ -764,7 +784,8 @@
 			in_dpf = DPF_OUTSIDE;
 			break;
 		case ACPI_RESOURCE_TYPE_IRQ:
-			KKASSERT(i < sc->pl_num_links);
+			if (i >= sc->pl_num_links)
+				break;	/* more IRQ resources than links */
 			res->Data.Irq.InterruptCount = 1;
 			if (PCI_INTERRUPT_VALID(link->l_irq)) {
 				KASSERT(link->l_irq < NUM_ISA_INTERRUPTS,
@@ -777,7 +798,8 @@
 			i++;
 			break;
 		case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
-			KKASSERT(i < sc->pl_num_links);
+			if (i >= sc->pl_num_links)
+				break;	/* more IRQ resources than links */
 			res->Data.ExtendedIrq.InterruptCount = 1;
 			if (PCI_INTERRUPT_VALID(link->l_irq))
 				res->Data.ExtendedIrq.Interrupts[0] =
@@ -893,7 +915,8 @@
 		switch (resource->Type) {
 		case ACPI_RESOURCE_TYPE_IRQ:
 		case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
-			KKASSERT(i < sc->pl_num_links);
+			if (i >= sc->pl_num_links)
+				break;	/* more IRQ resources than links */
 
 			/*
 			 * Only configure the interrupt and update the
@@ -1009,6 +1032,8 @@
 	best_weight = INT_MAX;
 	for (i = 0; i < link->l_num_irqs; i++) {
 		pos_irq = link->l_irqs[i];
+		if (pos_irq < 0 || pos_irq >= NUM_ACPI_INTERRUPTS)
+			continue;
 		if (pos_irq < NUM_ISA_INTERRUPTS &&
 		    (pci_link_bios_isa_irqs & 1 << pos_irq) == 0)
 			continue;
@@ -1023,7 +1048,8 @@
 	 * If this is an ISA IRQ and SCI could be shared, try using
 	 * the SCI as a fallback.
 	 */
-	if (link->l_isa_irq && acpi_sci_pci_shareable()) {
+	if (link->l_isa_irq && AcpiGbl_FADT.SciInterrupt < NUM_ACPI_INTERRUPTS &&
+	    acpi_sci_pci_shareable()) {
 		pos_irq = AcpiGbl_FADT.SciInterrupt;
 		pos_weight = pci_link_interrupt_weights[pos_irq];
 		if (pos_weight < best_weight) {