⬢ DragonFlyBSD Kernel Audit
DF-5431 / fix.diff
← back to finding ↓ download raw
--- a/sys/platform/pc64/acpica/acpi_madt.c
+++ b/sys/platform/pc64/acpica/acpi_madt.c
@@ -570,6 +570,8 @@
 struct madt_ioapic_probe_cbarg {
 	int	ioapic_cnt;
 	int	gsi_base0;
+	uint32_t ioapic_addrs[16];	/* IOAPIC_COUNT_MAX */
+	uint32_t gsi_bases[16];		/* IOAPIC_COUNT_MAX */
 };
 
 static int
@@ -615,10 +617,30 @@
 	} else if (ent->Type == ACPI_MADT_TYPE_IO_APIC) {
 		const ACPI_MADT_IO_APIC *ioapic_ent;
 
+		int i;
+
 		ioapic_ent = (const ACPI_MADT_IO_APIC *)ent;
 		if (ioapic_ent->Address == 0) {
 			kprintf("madt_ioapic_probe: zero IOAPIC address\n");
 			return EINVAL;
+		}
+		if (arg->ioapic_cnt >= 16) {	/* IOAPIC_COUNT_MAX */
+			kprintf("madt_ioapic_probe: too many IOAPICs\n");
+			return EINVAL;
+		}
+		for (i = 0; i < arg->ioapic_cnt; ++i) {
+			/*
+			 * Two IO APICs sharing an address or a GSI base
+			 * always overlap (every IO APIC has >= 1 pin);
+			 * ioapic_add() would panic() on it later.
+			 */
+			if (ioapic_ent->Address == arg->ioapic_addrs[i] ||
+			    ioapic_ent->GlobalIrqBase == arg->gsi_bases[i]) {
+				kprintf("madt_ioapic_probe: IOAPIC %d overlaps "
+				    "IOAPIC %d (addr/GSI base)\n",
+				    arg->ioapic_cnt, i);
+				return EINVAL;
+			}
 		}
 		if (ioapic_ent->Id == APICID_MAX) {
 			kprintf("madt_ioapic_probe: "
@@ -627,6 +649,8 @@
 			return EINVAL;
 		}
 
+		arg->ioapic_addrs[arg->ioapic_cnt] = ioapic_ent->Address;
+		arg->gsi_bases[arg->ioapic_cnt] = ioapic_ent->GlobalIrqBase;
 		arg->ioapic_cnt++;
 		if (ioapic_ent->GlobalIrqBase == 0)
 			arg->gsi_base0 = 1;