# DF-3286 VERDICT — REPRODUCED (memory write proven on stock kernel; silent on this build's stack layout)

## Bottom line

The 6-byte out-of-bounds stack write is **proven to execute on the stock
kernel**, by three mutually-independent pieces of evidence:

1. **Source math** (certain): `meshdrlen = 6 + 3*6 = 24` for AE=11,
   `hdrspace = 32` (DSTODS QoS), so `mesh_decap(..., hdrlen=56, ...)` is
   handed 56 bytes for a `uint8_t b[50]` (`sizeof(qosframe_addr4)=32` +
   `sizeof(meshcntl_ae10)=18`) at sys/.../ieee80211_mesh.c:1281-1296,
   1738-1741.

2. **Shipped-binary disassembly**: in /boot/kernel/kernel (mesh_decap
   inlined at mesh_input+0xae2):
   `lea -0x62(%rbp),%r14` (b base) … `rep movsb` with count loaded from
   the hdrlen slot (-0x90(%rbp)) — the destination object is 50 bytes
   (rbp-0x62..rbp-0x31) and the runtime count is 56, so bytes
   rbp-0x30..rbp-0x2b are written out of object bounds. Those 6 bytes are
   the frame's would-be `mc_addr6` (fully attacker-chosen; 0xCC pattern
   in the PoC).

3. **Runtime reachability** (stock guest, fwm harness): after
   `sysctl kern.fwm_step=10`, `is_mesh_badae` increments — that counter
   is bumped at ieee80211_mesh.c:1339 *after* the memcpy, proving the
   copy executed on the live kernel. 21 consecutive frames: guest stays
   up.

## Why no panic on this build

The overflow region rbp-0x30..rbp-0x2b is stack padding in this exact
gcc 8.3 -O2 INVARIANTS build (saved registers begin at rbp-0x28, 2 bytes
further up; no spill slot or local is addressed in the overflow window —
verified by scanning the full mesh_input disassembly). The bug is
nonetheless a genuine CWE-787 stack OOB write whose impact is
compiler-layout-dependent: 6 more bytes would reach saved rbx; any
relayout that places a live local or spill immediately above `b[]`
converts this into stack corruption of a pointer/int with
attacker-controlled data on a remote unauthenticated-after-peering path.

## Exploit chain (honest ceiling)

none on this build (padding). Primitive: 6 controlled bytes at fixed
offset above a 50-byte stack array in the RX path of every mesh data
frame; rate-unlimited from any established peer.

## Fix validation

Combined fix kernel (fix.diff hunk #4: reject `ae > IEEE80211_MESH_AE_10`
in mesh_input before meshdrlen math) built rc=0, rebooted, re-run:
- AE=11 frame now discarded at the new early gate (frame never reaches
  mesh_decap; disassembly of the fixed kernel shows the new branch);
- legal AE=00 data frames still decap and deliver normally (no
  regression);
- guest stays up across the full battery.
See fix section of run.log / fix notes in manifest.json.

## Reproduce

see README.md; harness in this directory (fwm.c).

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