DF-1113 / fix.diff
diff --git a/sys/platform/pc64/acpica/acpi_sdt.c b/sys/platform/pc64/acpica/acpi_sdt.c --- a/sys/platform/pc64/acpica/acpi_sdt.c +++ b/sys/platform/pc64/acpica/acpi_sdt.c @@ -49,6 +49,14 @@ kprintf("ACPI SDT: " fmt , ##arg); \ } while (0) +/* + * Sanity upper bound on the size of a single ACPI table. Legitimate + * firmware tables are well under 1 MB; this guard rejects malicious or + * buggy Length values near UINT32_MAX that would otherwise drive a + * multi-GiB kmem_alloc_nofault in pmap_mapdev_attr and panic the boot. + */ +#define SDT_MAX_TABLE_SIZE (1U * 1024 * 1024) + typedef vm_paddr_t (*sdt_search_t)(vm_paddr_t, const uint8_t *); static const ACPI_TABLE_RSDP *sdt_rsdp_search(const uint8_t *, int); @@ -147,6 +155,18 @@ if (mapsz < sizeof(*sdth)) return NULL; + /* + * Reject obviously-malformed / malicious firmware Length values. + * The largest legitimate ACPI table is well under 1 MB (the DSDT + * on this guest is 0x1AF8 bytes); a Length near UINT32_MAX makes + * pmap_mapdev_attr attempt a multi-GiB kmem_alloc_nofault that + * fails and panics ("pmap_mapdev: Couldn't alloc kernel virtual + * memory", pmap.c:6203). Cap the mapping at a generous upper + * bound so buggy / malicious firmware can't panic the boot. + */ + if (mapsz > SDT_MAX_TABLE_SIZE) + return NULL; + return pmap_mapdev(paddr, mapsz); } |