DragonFlyBSD Kernel Audit
DF-1113 / df1113.c
← back to finding ↓ download raw
/*
 * 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; }