# DF-3328 — 1 byte of uninitialized kernel heap broadcast in forwarded HWMP PERRs

**File:** `sys/netproto/802_11/wlan/ieee80211_hwmp.c`
**Severity:** Low (kernel heap info-leak over the air, 1 byte per forwarded PERR)
**Verdict:** REPRODUCED — forwarded PERR TTL byte provably never sourced from
the received frame; constant prior-heap contents (`0xff` block → emitted
`0xfe`) across 18 triggers / 3 boots / both kernels.

## What

`hwmp_recv_perr()` allocates the propagation PERR **without M_ZERO**
(`ieee80211_hwmp.c:1743-1748`, contrast the RX-path allocations at
`:430-439`/`:530-537` which use `M_ZERO`) and **never initializes
`pperr->perr_ttl`**: the only touch is `pperr->perr_ttl--` at `:1823`, after
which `hwmp_send_perr` → `hwmp_add_meshperr` (`:784`) writes that byte into
a **broadcast** PERR action frame. Every mesh neighbor receives one byte of
whatever previously occupied that heap block.

Trigger chain (all remote, after auto-peering):
1. PREP with `origaddr == victim` (skips propagation), `targetaddr = Y`,
   `ttl=1` → victim creates a VALID route for Y with nexthop = attacker
   (`ieee80211_hwmp.c:1427-1513`).
2. PERR with `dest_flags = 62` (numerically equal to
   `IEEE80211_REASON_MESH_PERR_NO_FI` — hits the switch on the wrong field,
   cf. DF-0353), `dest = Y`, `seq = 0`, `ttl = N > 1` → route invalidated,
   PERR accepted and **forwarded** (`:1814-1824`) with the uninitialized TTL.

## Reproduce

    sh findings/poc/DF-3328/build.sh
    sh findings/poc/DF-3328/run.sh        # 5 rounds PREP+PERR, varying rx TTL
    # forwarded frames: sysctl kern.fwm_txlog  (hex; TTL = byte offset 28)

Expected: every forwarded PERR (43 bytes, IE 132 at offset 26) carries
`ttl = 0xfe` while a spec-conforming implementation would send `rx_ttl - 1`
(4, 8, 199, 76, 249, …). The emitted value matches no byte of any injected
frame and is stable per heap state (see `leak_sample.txt`).

## Fix

Initialize the propagated TTL from the received frame:

```diff
 		pperr->perr_ndests = j;
-		pperr->perr_ttl--;
+		pperr->perr_ttl = perr->perr_ttl - 1;
 		hwmp_send_perr(vap, broadcastaddr, pperr);
```

(and/or add `M_ZERO` to the `pperr` allocation for defense in depth).
