⬢ DragonFlyBSD Kernel Audit
DF-5432 / fix.diff
← back to finding ↓ download raw
diff --git a/sys/platform/pc64/acpica/acpi_madt.c b/sys/platform/pc64/acpica/acpi_madt.c
index 0e2b2ac..1111111 100644
--- a/sys/platform/pc64/acpica/acpi_madt.c
+++ b/sys/platform/pc64/acpica/acpi_madt.c
@@ -44,6 +44,7 @@
 #include <machine_base/acpica/acpi_md_cpu.h>
 #include <machine/specialreg.h>
 
+#include <vm/pmap.h>
 #include <contrib/dev/acpica/source/include/acpi.h>
 
 #include "acpi_sdt_var.h"
@@ -572,6 +573,23 @@ struct madt_ioapic_probe_cbarg {
 	int	gsi_base0;
 };
 
+static boolean_t
+madt_ioapic_addr_in_ram(uint32_t addr)
+{
+	int i;
+
+	/* phys_avail[] holds the available-RAM segments, populated by
+	 * MD boot code long before SI_BOOT2_PRESMP.  Device MMIO never
+	 * lives inside them.  DF-5432.
+	 */
+	for (i = 0; phys_avail[i].phys_end != 0; ++i) {
+		if (addr >= phys_avail[i].phys_beg &&
+		    addr < phys_avail[i].phys_end)
+			return TRUE;
+	}
+	return FALSE;
+}
+
 static int
 madt_ioapic_probe_callback(void *xarg, const ACPI_SUBTABLE_HEADER *ent)
 {
@@ -620,6 +641,19 @@ madt_ioapic_probe_callback(void *xarg, const ACPI_SUBTABLE_HEADER *ent)
 			kprintf("madt_ioapic_probe: zero IOAPIC address\n");
 			return EINVAL;
 		}
+		if (madt_ioapic_addr_in_ram(ioapic_ent->Address)) {
+			/*
+			 * An I/O APIC register file is device MMIO; it
+			 * never lives in system RAM.  A MADT claiming
+			 * so is malicious or corrupt -- reject it before
+			 * ioapic_map() hands the page to ioapic_read()/
+			 * ioapic_write() as a register file.
+			 */
+			kprintf("madt_ioapic_probe: IOAPIC address %#x in "
+			    "system RAM, rejecting MADT\n",
+			    ioapic_ent->Address);
+			return EINVAL;
+		}
 		if (ioapic_ent->Id == APICID_MAX) {
 			kprintf("madt_ioapic_probe: "
 			    "invalid IOAPIC apic id %d\n",