# DF-5430 — VERDICT

## 1. Reproduced? YES — real kernel-boot panic, twice

| run | kernel | result |
|-----|--------|--------|
| run.log  | 6.5-DEVELOPMENT #0 Thu Jul 2 06:02:54 (with-src build) | panic at acpi_madt.c:375 |
| run.2.log| v6.5.0.1712.g89e6a #1 Mon Jun 29 (clean-install build) | panic at acpi_madt.c:375 |

Decisive lines (run.log:43-44, run.2.log:43-44):

```
madt_lapic_probe: lapic_count=2 x2apic_count=0
panic: assertion "arg.bsp_found" failed in madt_lapic_pass2 at /usr/src/sys/platform/pc64/acpica/acpi_madt.c:375
```

## 2. Why it is real (path:line)

* Probe aggregates only entry COUNTS: `madt_lapic_probe_callback`
  (acpi_madt.c:391-407) increments `lapic_count` for every enabled entry and
  rejects only `Id == APICID_MAX`. `madt_lapic_probe` (acpi_madt.c:453-488)
  checks `lapic_count == 0` and the LAPIC address — it never compares any
  entry against the hardware BSP APIC ID that `madt_lapic_enumerate`
  obtains from `LAPIC_READID` (acpi_madt.c:533).
* Enumerate then runs pass2, where the only BSP sanity is
  `KKASSERT(arg.bsp_found)` (acpi_madt.c:375). On the guest's INVARIANTS
  kernel (sys/config/X86_64_GENERIC:56) that is an unconditional
  `panic("assertion ...")` (sys/sys/systm.h:98).
* On non-INVARIANTS kernels `KKASSERT` compiles to nothing
  (sys/sys/systm.h:118); `naps` is computed from the table and slot 0 keeps
  the BSS-zero `cpu_id_to_apic_id[0] == 0` (lapic.c:122; init hole documented
  by DF-5366) — a hardware BSP with ID != 0 then gets every cpu-0-targeted
  IPI delivered to the wrong local APIC.

This is the MADT sibling of mptable's DF-5339 (probe/enumerate
BSP-validation asymmetry) — same defect shape, different table.

## 3. Threat model / preconditions

The MADT is firmware-fed. Arming it requires control of the ACPI tables
presented at boot: malicious/compromised hypervisor host, crafted UEFI
firmware, a bootloader-kenv override (`hint.acpi.0.rsdp=<phys>`, the exact
vector used here — it performs zero validation, acpi_sdp.c:71), or any
console/loader access. No unprivileged in-guest path exists. Deterministic
boot-time DoS (panic) on INVARIANTS kernels; silent cpu-0 mis-addressing on
production kernels. Low severity per the project's accepted bar for this
class (DF-1034, DF-5339).

## 4. Exploit chain

None — boot-time firmware-fed DoS. No memory-corruption primitive: the panic
is a controlled assertion failure before any OOB write (the cpu counter
stays small; the OOB-counter variant is DF-1064, not re-reported here).

## 5. Fix

`fix.diff` converts the assert into graceful enumeration failure:
`madt_lapic_pass2` returns `EINVAL`, `madt_lapic_enumerate` propagates it,
and `lapic_config()` (lapic.c:1268-1272) already handles enumerate errors
("LAPIC: enumeration failed", tries the next enumerator / ENXIO) — the
machine degrades instead of panicking. `git apply --check` passes against
the read-only sys/ tree. Fix not kernel-build-validated in this run: the
single mandatory build slot was spent on the memory-corruption finding
DF-5432 (same-run budget; this finding is a Low boot-time panic).

## Fix status (batch validation)
Applied with the 36 sibling fix.diffs of this batch in findings/poc/_batch41/all_fixes.patch; single in-guest `make -j6 nativekernel KERNCONF=X86_64_GENERIC` completed RC=0 with zero errors under -Werror (full log: findings/poc/_batch41/fix_build8.log). Behavior A/B intentionally skipped for this Info-tier item.
