# DF-0349 — Heap OOB read in PREQ processing when target count is 0

## Verdict: REAL (source-trace confirmed) — not testable on this guest (no WiFi HW)

## Mechanism

`verify_mesh_preq_len()` at `sys/netproto/802_11/wlan/ieee80211_hwmp.c:311-336`
returns `ndest` which can be 0 (reads a byte from the frame at
`:320`/`:324`). The length check at `:328` passes with `ndest==0`
when `iefrm[1] == IEEE80211_MESHPREQ_BASE_SZ` (26). Returns 0 — the
`if (ndest < 0)` guard at `:426` does NOT catch 0.

The caller at `:431-433`:
```c
preq = kmalloc(sizeof(*preq) +
    (ndest - 1) * sizeof(*preq->preq_targets), ...);
```

With `ndest=0`:
- `(ndest - 1)` = -1 (int)
- Implicit conversion to `size_t` → `SIZE_MAX` (0xFFFFFFFFFFFFFFFF)
- `SIZE_MAX * sizeof(target)` = wraps: `sizeof(*preq) - sizeof(target)`
  = 45 - 11 = **34 bytes** allocated

`preq_targets[0]` starts at offset 34 in the struct. DragonFly's slab
allocator (`zoneindex()` at `kern_slaballoc.c:642-645`) rounds 34 →
**40 bytes** (next multiple of 8). So:
- Bytes 34-39: within the 40-byte slab chunk (padding, zeroed by M_ZERO)
- **Bytes 40-44: 5 bytes OOB** — past the slab chunk into adjacent
  object or slab metadata

`hwmp_recv_preq()` at `:1005` unconditionally derefs
`PREQ_TADDR(0)` = `preq->preq_targets[0].target_addr` (offset 35-40)
and `PREQ_TSEQ(0)` (offset 41-44), reading **5 bytes of OOB heap**.

The OOB bytes are used as:
- An ethernet address for `ether_sprintf()` (printed to kernel log)
- A lookup key for `ieee80211_mesh_rt_find()`

## Privilege / testability

- Remote-triggerable: any WiFi mesh peer can send a crafted PREQ with
  `target_count=0`.
- The wlan + mesh code IS compiled into the GENERIC kernel
  (`device wlan`, `options IEEE80211_SUPPORT_MESH`).
- But requires WiFi hardware to receive mesh frames — **none on this
  guest**.
- The `wlan` module is not loaded at runtime (no WiFi interfaces).

This is a **valid hard blocker**: the code path is unreachable at
runtime on this guest (no WiFi hardware to receive PREQ frames).

## Fix

`fix.diff` — add `if (ndest < 1)` rejection in
`verify_mesh_preq_len()` after the length check. A PREQ with zero
targets is invalid per IEEE 802.11s and would cause the OOB. The fix
is compiled and verified to build cleanly on GENERIC.

## Impact

Remote heap OOB read (~5 bytes) from an unauthenticated WiFi mesh
peer. Info leak of adjacent slab data + potential route corruption
(the OOB bytes are used as a route lookup key). Realistic only in a
mesh WiFi deployment with HWMP routing enabled.
