diff options
author | Mark Kettenis <kettenis@cvs.openbsd.org> | 2009-02-16 20:11:07 +0000 |
---|---|---|
committer | Mark Kettenis <kettenis@cvs.openbsd.org> | 2009-02-16 20:11:07 +0000 |
commit | 754f4fc24d729ee82c61d1ed0630fe5c288eb2a8 (patch) | |
tree | 14463a2e66c8e9a05b4cbcc2c029c012e0c65aed /sys/dev/acpi | |
parent | 51e3bbf4609ab0115efc65c0407631c19c44aaf7 (diff) |
Be a litte bit more paranoid and validate the APIC table before committing
to APIC mode.
tested by many
ok marco@
Diffstat (limited to 'sys/dev/acpi')
-rw-r--r-- | sys/dev/acpi/acpimadt.c | 69 |
1 files changed, 68 insertions, 1 deletions
diff --git a/sys/dev/acpi/acpimadt.c b/sys/dev/acpi/acpimadt.c index ca64cdea1d2..e0a8c9fd66b 100644 --- a/sys/dev/acpi/acpimadt.c +++ b/sys/dev/acpi/acpimadt.c @@ -1,4 +1,4 @@ -/* $OpenBSD: acpimadt.c,v 1.21 2008/09/15 19:25:36 kettenis Exp $ */ +/* $OpenBSD: acpimadt.c,v 1.22 2009/02/16 20:11:06 kettenis Exp $ */ /* * Copyright (c) 2006 Mark Kettenis <kettenis@openbsd.org> * @@ -53,6 +53,7 @@ struct cfdriver acpimadt_cd = { NULL, "acpimadt", DV_DULL }; +int acpimadt_validate(struct acpi_madt *); void acpimadt_cfg_intr(int, u_int32_t *); int acpimadt_print(void *, const char *); @@ -78,6 +79,66 @@ acpimadt_match(struct device *parent, void *match, void *aux) return (1); } +int +acpimadt_validate(struct acpi_madt *madt) +{ + caddr_t addr = (caddr_t)(madt + 1); + + while (addr < (caddr_t)madt + madt->hdr.length) { + union acpi_madt_entry *entry = (union acpi_madt_entry *)addr; + u_int8_t length = entry->madt_lapic.length; + + if (length < 2) + return (0); + + if (addr + length > (caddr_t)madt + madt->hdr.length) + return (0); + + switch (entry->madt_lapic.apic_type) { + case ACPI_MADT_LAPIC: + if (length != sizeof(entry->madt_lapic)) + return (0); + break; + case ACPI_MADT_IOAPIC: + if (length != sizeof(entry->madt_ioapic)) + return (0); + break; + case ACPI_MADT_OVERRIDE: + if (length != sizeof(entry->madt_override)) + return (0); + break; + case ACPI_MADT_NMI: + if (length != sizeof(entry->madt_nmi)) + return (0); + break; + case ACPI_MADT_LAPIC_NMI: + if (length != sizeof(entry->madt_lapic_nmi)) + return (0); + break; + case ACPI_MADT_LAPIC_OVERRIDE: + if (length != sizeof(entry->madt_lapic_override)) + return (0); + break; + case ACPI_MADT_IO_SAPIC: + if (length != sizeof(entry->madt_io_sapic)) + return (0); + break; + case ACPI_MADT_LOCAL_SAPIC: + if (length != sizeof(entry->madt_local_sapic)) + return (0); + break; + case ACPI_MADT_PLATFORM_INT: + if (length != sizeof(entry->madt_platform_int)) + return (0); + break; + } + + addr += length; + } + + return (1); +} + struct mp_bus acpimadt_busses[256]; struct mp_bus acpimadt_isa_bus; @@ -131,6 +192,12 @@ acpimadt_attach(struct device *parent, struct device *self, void *aux) int nlapic_nmis = 0; int pin; + /* Do some sanity checks before committing to run in APIC mode. */ + if (!acpimadt_validate(madt)) { + printf(": invalid, skipping\n"); + return; + } + printf(" addr 0x%x", madt->local_apic_address); if (madt->flags & ACPI_APIC_PCAT_COMPAT) printf(": PC-AT compat"); |