⬢ DragonFlyBSD Kernel Audit
DF-5365 / fix.diff
← back to finding ↓ download raw
--- a/sys/platform/pc64/apic/lapic.c
+++ b/sys/platform/pc64/apic/lapic.c
@@ -1081,6 +1081,27 @@
 void
 lapic_map(vm_paddr_t lapic_addr)
 {
+	vm_paddr_t hw_addr;
+
+	/*
+	 * DF-5365: The LAPIC register-page address comes from firmware
+	 * tables (MADT LocalApicAddr / MP config table apic_address) and
+	 * was previously mapped with no validation at all, giving a
+	 * crafted table an arbitrary-physical-address kernel read/write
+	 * page at boot.  Cross-check it against the CPU's own
+	 * IA32_APICBASE MSR, which cannot lie about where the local APIC
+	 * actually is, and fall back to the hardware value on mismatch.
+	 */
+	hw_addr = (vm_paddr_t)(rdmsr(MSR_APICBASE) & ~0xFFFULL);
+	if (lapic_addr == 0 || (lapic_addr & PAGE_MASK) != 0 ||
+	    lapic_addr != hw_addr) {
+		kprintf("LAPIC: bogus LAPIC address 0x%llx in firmware table, "
+		    "using 0x%llx from APIC base MSR\n",
+		    (unsigned long long)lapic_addr,
+		    (unsigned long long)hw_addr);
+		lapic_addr = hw_addr;
+	}
+
 	lapic_mem = pmap_mapdev_uncacheable(lapic_addr, sizeof(struct LAPIC));
 }