# DF-5340 — `(base_memory - 1) * 1024` underflow in the mptable base-memory scan (DF-5326 class)

## Verdict: **defect certain at code level; arithmetic proven on the audited guest; kernel-boot manifestation untested** (needs crafted loader SMAP + empty EBDA; strictly dominated in blast radius by DF-5326, but a distinct unguarded instance in this file)

## 1. Root cause

`sys/platform/pc64/x86_64/mptable.c:270-301`, `mptable_search()`:

```c
if (ebda_addr != 0) {
	target = (u_int32_t)ebda_addr;
	if ((x = mptable_search_sig(target, 1024 / 4)) > 0)
		return x;
} else {
	/* last 1K of base memory, effective 'top of base' passed in */
	target = (u_int32_t)((base_memory - 1) * 1024);		/* mptable.c:284 */
	if ((x = mptable_search_sig(target, 1024 / 4)) > 0)
		return x;
}
```

and `mptable_search_sig()`:

```c
KKASSERT(target != 0);					/* mptable.c:368 */
map_size = count * sizeof(u_int32_t);
addr = pmap_mapdev((vm_paddr_t)target, map_size);	/* mptable.c:371 */
```

Inputs (both firmware/loader-controlled, no lower bound anywhere):

* `base_memory` (u_int, KB) = `physmap[1] / 1024` — `machdep.c:2270`, built
  from the loader-supplied `MODINFOMD_SMAP`/EFI map. **This is exactly the
  input DF-5326 proved can be degenerate** (`findings/poc/DF-5326/`).
* `ebda_addr` = `*(u_short *)(KERNBASE + 0x40e) << 4` — `machdep.c:2275-2276`;
  the else-branch is reached when the BDA EBDA pointer is zero.

Unsigned consequences in `u_int`:

| base_memory | `(base_memory-1)*1024` (mod 2^32) | effect |
|-------------|-----------------------------------|--------|
| 0           | 0xFFFFFC00                        | `pmap_mapdev(0xFFFFFC00, 1024)` — top-of-4GB MMIO hole; span `0xFFFFFC00+0x400` **wraps past 4GB**; the intended base-memory scan never happens; reads garbage (0xFF on QEMU, machine-check-class on some real HW) |
| 1           | 0x00000000                        | `KKASSERT(target != 0)` fails → **boot-time kernel panic** (INVARIANTS kernels; X86_64_GENERIC:56) |
| ≥ 2         | intended last-1K-of-base region   | correct |

`pmap_mapdev_attr()` (`pmap.c:6192-6218`) validates nothing — it installs PTEs
for ANY physical address.

## 2. Reproduction (verbatim arithmetic, on the audited guest)

`basemem_scan_underflow.c` copies the else-branch and the KKASSERT verbatim.
`run.log` (guest `cc 8.3`):

```
  base_memory=0    -> target=0xfffffc00  scan [fffffc00..00000000]: WRAPPED past 4GB, top-of-4GB MMIO hole, not base memory
  base_memory=1    -> target=0x00000000  KERNEL PANIC -> assertion "target != 0" failed in mptable_search_sig at mptable.c:368
  base_memory=2    -> target=0x00000400  scan [00000400..00000800]: sane region
  ...
  base_memory=639  -> target=0x0009f800  scan [0009f800..0009fc00]: sane region
```

The `639` row is the real SeaBIOS value on this guest class — healthy firmware
never trips this; a degenerate first usable region (`physmap[1] < 2048`) does.
Note DF-5326's `mp_bootaddress(base_memory)` fires on the *same* input and
corrupts `physmap[1]` itself, so on a real system both defects manifest
together; this file's instance is reported separately because it is a distinct
function with a distinct sink (mapdev/KKASSERT vs physmap corruption) and is
fixed independently.

## 3. Why kernel-boot manifestation is untested

Arming requires a loader-supplied SMAP whose first usable region ends below
2048 bytes AND a zero BDA EBDA pointer. Stock QEMU/SeaBIOS builds neither
(`etc/e820` fw_cfg only adds reserved regions); no unprivileged in-guest actor
reaches `mptable_search()` — it runs exactly once at `SI_BOOT2_PRESMP`
(`mptable.c:265`).

## 4. Recommended fix

`fix.diff` — only take the base-memory branch when `base_memory > 1`, leaving
the BIOS-area scans as the fallback (a system with < 2 KB of base memory has
no MP floating pointer worth finding).

## 5. Fix validation

`git apply --check` passes. Patched-kernel boot comparison is not
constructible on this guest (same injection constraint), hence
`fix_status: not_testable`.

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