DF-1113 / df1113.c
/* * DF-1113 — minimal proof of the sdt_sdth_map unbounded ACPI table Length. * * The bug is in `sdt_sdth_map` at acpi_sdt.c:137-151. The firmware-supplied * uint32 `sdth->Length` is passed directly to `pmap_mapdev` as the mapping * size after only a *lower* bound check (`mapsz < sizeof(*sdth)` at :147). * * sdth = pmap_mapdev(paddr, sizeof(*sdth)); // map header * mapsz = sdth->Length; // :144, unbounded * pmap_unmapdev((vm_offset_t)sdth, sizeof(*sdth)); * if (mapsz < sizeof(*sdth)) return NULL; // :147, lower bound only * return pmap_mapdev(paddr, mapsz); // :150, unbounded * * pmap_mapdev_attr at pmap.c:6191-6222 calls kmem_alloc_nofault with the * raw size; for a Length near UINT32_MAX that alloc fails and the kernel * panics: * * panic("pmap_mapdev: Couldn't alloc kernel virtual memory") // pmap.c:6203 * * sdt_search_xsdt/rsdt compute nent from the same unbounded Length * (acpi_sdt.c:194 / :255) and call sdt_sdth_map in a loop on * attacker-named physical addresses, so a single fat XSDT/RSDT can * detonate on every entry. * * sdt_sdth_map runs from `sdt_probe` (SYSINIT SI_BOOT2_PRESMP, before * userland). An attacker controls the tables via: * - malicious / buggy firmware, * - loader hint `hint.acpi.0.rsdp=<phys>` pointing at a crafted RSDP, * - a malicious hypervisor controlling guest ACPI. * * The audit guest boots cleanly (its BOCHS firmware supplies well-formed * tables), and re-booting under malicious firmware is outside the audit's * runtime threat model. The bug is *latent* — confirmed by source trace. * * The fix is in fix.diff: clamp mapsz to SDT_MAX_TABLE_SIZE (1 MB) inside * sdt_sdth_map after the lower-bound check, so an attacker-controlled * Length near UINT32_MAX is rejected instead of panicking. */ int main(void) { return 0; } |