# DF-4686 -- verdict narrative

## What was claimed
FillVpdTable/interpolate span never clamped (ar2425 twin of DF-4683): descending curve -> (uint16_t)(Pmax-Pmin) wrap -> ~131 KB sequential OOB write past the function-static VpdTable_* block in kernel static storage; valid curve spanning >63 half-dB -> OOB write past the block with NO wrap

## Reproduced?
YES (mode 4 and 5 of the shared verbatim-extraction harness, run on the DragonFly guest).

REPRODUCED on the DragonFly guest (verbatim-extraction harness, modes 4 and 5) -- the ar2425 twin of DF-4683 with an ar2425-specific twist: ar2425.c keeps VpdTable_L/R/I + Pmin_t2/Pmax_t2 as FUNCTION-SCOPE STATICS (ar2425.c:367-379), not struct members like the ar2317/ar2316/ar2413/ar5413 twins, so the span overflow marches through KERNEL STATIC STORAGE (adjacent .bss symbols), not a heap object. Neither ar2425FillVpdTable's loop (bound = (uint16_t)(Pmax-Pmin) at ar2425.c:311, store at :325) nor the interpolate loop (:419-424) clamps the span to the 64-wide row or rejects Pmax<Pmin. (Mode 4) a DESCENDING pwr_t4 curve yields Pmax_t2=84 < Pmin_t2=90 (the :398-408 min() across idxL/idxR performs no monotonicity check), the bound wraps to 65530 -> 131060 bytes of uint16 stores from VpdTable_L[0][0] through the whole 1552-byte statics block and off its end; the harness faulted on the STORE at exactly the block end (guard page, exact match). (Mode 5) a VALID ascending curve spanning 102 half-dB needs no wrap: FillVpdTable spills rows L[3]/R[3][64..] into neighboring statics, and the interpolate loop writes VpdTable_I[3][0..101]; I[3][64] lands on Pmin_t2 (kernel: adjacent .bss), clobbers the loop's own re-evaluated bound to a uint16-wrapped ~65535 and the march continues off the block end (fault exact-match). Values written are EEPROM-Vpd-derived. REACHABILITY (honest, refines DF-4683's framing): through the ONLY constructor (readEepromRawPowerCalInfo2413 -> ar2413EepromToRawDataset, ah_eeprom_v3.c:703-747) pwr deltas are UNSIGNED 4-bit fields (dbm_delta_mask=0xF, ah_eeprom_v3.c:450) summed cumulatively, so every pier curve is provably non-descending with span <= 4x15=60 half-dB: neither variant is constructible from EEPROM bits TODAY -- the missing clamp is latent/defense-in-depth (any decoder change, a divergent caller, or an eeprom v>5 re-arm it). Filed as the family twin DF-4683 explicitly flagged at ar2425.c:311. Fix validated: fixD (reject inverted/oversized spans) alone completes mode 5; mode 4 completes with fixD+fixB (skipping the inverted gain leaves zero gains -- DF-4688's early return covers the residual).

## Fix validation
Harness-level validation (fix_validate.sh): baseline modes 4/5 fault at the statics-block guard on the unpatched build; with fixD applied, mode 5 completes; mode 4 completes with fixD+fixB (residual zero-gain path after skipping the inverted gain). No kernel rebuild: no AR2425 hardware on the guest, the fix is validated against the verbatim-extracted function bodies per the family methodology (DF-4619..DF-4683).

Decisive evidence: run.log: 'mode 4 ... si_addr is 1552 bytes past block start (sizeof=1552) ... MATCH' and 'mode 5 ... MATCH'; fix_run.log: 'PATCHED mode 5 with fixD only ... no SIGSEGV' and 'PATCHED mode 4 with fixB+fixD ... no SIGSEGV'.

## Why no in-kernel run
The guest has no AR2425 NIC and no EEPROM-injection path; the family methodology
(DF-4619..DF-4683, all accepted with the same constraint) compiles the real function
bodies against faithful struct/static layouts and proves the violation with
exact-address faults / canaries / propagation -- equivalent strength for a
hardware-gated defect, and it validates the fix the same way.

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