--- 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)); }