# DF-5650 VERDICT — REPRODUCED (OOB read: console info leak + boot-time kernel page fault)

## 1. Bottom line

The SRAT entry walk reads affinity-structure fields with no check that the
entry's declared `Length` fits inside the table or covers the structure.
Both observable consequences were reproduced live on the stock kernel:

1. **Content disclosure**: bytes physically adjacent to the table (planted
   markers at +0..+19 past the declared table end) were read by the kernel
   and printed to the console/dmesg as the `MemAffinity %016jx,%ldMB
   Prox=%u` line. Two identical runs (`run.log`, transcript re-run).
2. **Kernel page fault**: with the table ending exactly on a page boundary,
   the same field read crossed past the one-page `pmap_mapdev` mapping and
   took `Fatal trap 12` mid-boot at the literal gate instruction
   `testb $0x1,0x1c(%r12)` (= `mem->mem.Flags & ACPI_SRAT_MEM_ENABLED`,
   packed Flags u32@+28). Two identical runs (first capture in session
   transcript, `run.fault.log` after guest reset).

Both are gone on a kernel rebuilt with `fix.diff` (entries rejected with
`srat_probe: invalid SRAT entry len 48` before any field read;
`fixed_l3.log`, `fixed_f3.log`).

## 2. Root cause (path:line)

- `sys/platform/pc64/acpica/acpi_srat.c:93-95` — walk condition only bounds
  the entry's first byte; advance by `head.Length`; no
  `Length <= remaining` check.
- `sys/platform/pc64/acpica/acpi_srat.c:99-107` — `mem->mem.Flags` read
  (packed +28) and `BaseAddress/Length/ProximityDomain` (+8/+16/+2) read
  and printed with no `Length >= sizeof(struct)` check.
- `sys/platform/pc64/acpica/acpi_srat.c:114-135` — inner CPU scan reads
  `cpu->cpu.Flags/ProximityDomainLo/ApicId` with the same absence of checks.
- `sys/platform/pc64/acpica/acpi_sdt.c:138-151` — `sdt_sdth_map` maps
  exactly `Header.Length` bytes (page-rounded); reads past it hit adjacent
  physical RAM (leak flavor) or unmapped KVA (fault flavor;
  `pmap_mapdev_attr` allocates fresh KVA, `pmap.c:6192-6217`).
- Sibling contrast: `sys/platform/pc64/acpica/acpi_madt.c:151-167` —
  `madt_iterate_entries` enforces header-minimum, remaining-extent, and
  per-type minimum lengths. None of this exists for SRAT.

## 3. Threat model / impact ceiling

Firmware/loader-stage attacker (planted RSDP chain — DF-5588 vector;
malicious VM host; compromised loader config), same class as
DF-5430..5433/5583. The disclosed bytes are physical memory adjacent to the
(SRAM/ROM-resident) ACPI table — on real firmware, neighboring firmware
tables/EBDA content; not kernel heap. The fault flavor is a deterministic
boot DoS when the adjacency condition holds. No write primitive, no
unprivileged in-guest path → Medium.

## 4. Reproduction evidence

- `run.log` (leak3): declared SRAT Length=66; entry header `01 30` at +64;
  markers planted at table_end+0..3 (`54 41 52 53` → Prox=1397899604),
  +6..13 (`deadbeefcafe0123` → Base), +14..21 (`1122334455667788` →
  1177411667286 MB). Every printed value originates past the declared
  table end.
- `run.fault.log` (fault3): declared Length=0x800 ending on the
  0x40001000 boundary; serial shows `CPU Topology` (line 85) then
  `Fatal trap 12` (line 88) and `Stopped at -0x7f3de188: testb
  $0x1,0x1c(%r12)` — the flags gate reading entry+28 = 26 bytes past the
  mapped page. Boot dies at SI_BOOT2_NUMA (current process 0, no APs
  started).
- Marker bytes verified in the planted blob (`od` in session transcript);
  blob survival to kernel time proven by DF-5649's `wedge_page.bin` /
  `kdump_srat.bin` dumps (same placement).

## 5. Fix validation (baseline vs patched)

Same `fix.diff` as DF-5649 (adds header-minimum, remaining-extent, and
per-type minimum checks before any field read). Patched kernel
(`make nativekernel`, BUILD_OK, installed):

| flavor | baseline | patched |
|---|---|---|
| leak3 | `MemAffinity deadbeefcafe0123,...` (OOB bytes disclosed) | `srat_probe: invalid SRAT entry len 48`, no disclosure |
| fault3 | `Fatal trap 12` at `testb $0x1,0x1c(%r12)` in srat_probe | `srat_probe: invalid SRAT entry len 48`, no trap |

Both patched runs proceed past `SI_BOOT2_NUMA` (`vm_page: avg` line 87) to
the rig's normal endpoint (the DSDT-less AcpiTbLoadNamespace trap at
line ~352 — rig artifact present in every healthy boot of this rig,
see `control_baseline.log` line 351).

## 6. Rig notes

See `../DF-5649/DECODE_LOG.md` — packed struct offsets (the original
generator used aligned offsets and every crafted entry was silently
skipped), blob placement lifetime, and the boot-marker line map.

## 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.
