# DF-1113 — Unbounded ACPI table Length in sdt_sdth_map (boot panic)

## Claim
`sdt_sdth_map()` at `sys/platform/pc64/acpica/acpi_sdt.c:137-151`:

```c
void *
sdt_sdth_map(vm_paddr_t paddr)
{
    ACPI_TABLE_HEADER *sdth;
    vm_size_t mapsz;

    sdth = pmap_mapdev(paddr, sizeof(*sdth));     /* map the header */
    mapsz = sdth->Length;                          /* line 144 — firmware uint32 */
    pmap_unmapdev((vm_offset_t)sdth, sizeof(*sdth));

    if (mapsz < sizeof(*sdth))                     /* line 147 — lower bound only */
        return NULL;

    return pmap_mapdev(paddr, mapsz);              /* line 150 — unbounded */
}
```

The only validation is `mapsz < sizeof(*sdth)` (a *lower* bound of 36 bytes).
`mapsz` is the firmware-supplied `uint32 Length` field of an ACPI table
header — there is **no upper bound**.

`pmap_mapdev_attr` at `sys/platform/pc64/x86_64/pmap.c:6191-6222` does:
```c
size = roundup(offset + size, PAGE_SIZE);
va = kmem_alloc_nofault(kernel_map, size, VM_SUBSYS_MAPDEV, PAGE_SIZE);
if (va == 0)
    panic("pmap_mapdev: Couldn't alloc kernel virtual memory");
```

A `Length` near `UINT32_MAX` causes `kmem_alloc_nofault` to try to allocate
~4 GiB of kernel virtual memory. On a 4 GiB-RAM guest this fails
deterministically → panic.

`sdt_search_xsdt` / `sdt_search_rsdt` (acpi_sdt.c:159-279) compute `nent`
from the same unbounded `Length` (line 194-195 / 255-256), so a "fat" XSDT
or RSDT also drives a per-entry loop that calls `sdt_sdth_map` on
attacker-controlled physical addresses — every iteration can panic.

`sdt_sdth_map` is invoked from `acpi_sdt_*` initialisation, which runs at
`SI_BOOT2_PRESMP` (`SYSINIT`) — i.e. **boot-only**, before userland starts.
Attacker controls the ACPI tables via:
- malicious / buggy firmware (the realistic case),
- `loader` hint `hint.acpi.0.rsdp=` pointing at a crafted RSDP,
- a malicious hypervisor controlling guest ACPI.

## Reproducibility on this guest
The bug is boot-time only. The audit guest's BOCHS firmware supplies
well-formed ACPI tables (visible in dmesg: `RSDT ... 000034`, `DSDT ...
001AF8`, etc. — all reasonable lengths). The kernel boots cleanly and
reaches multi-user. To trigger the panic, we would need to reboot under a
malicious firmware or a `loader.conf` override pointing at a crafted RSDP
physical address — neither is in the threat model of an *audit* guest that
must keep running for the other tests.

The bug is **latent** — confirmed by source trace. The fix is purely
defensive against malicious/buggy firmware.

## Fix
`fix.diff`: clamp `mapsz` to an upper bound `SDT_MAX_TABLE_SIZE = 1 MB`
inside `sdt_sdth_map`, after the existing lower-bound check. Any ACPI table
larger than 1 MB is malformed (the largest legitimate table on this guest
is <8 KB), so the clamp rejects attacker-controlled lengths near UINT32_MAX
without breaking well-formed firmware.
