# DF-4619 VERDICT

## Finding
Unbounded `kk` in `ar5413getGainBoundariesAndPdadcsForPowers`
(sys/dev/netif/ath/ath_hal/ar5212/ar5413.c:397-540) writes past
`pcdacTable[PWR_TABLE_SIZE_2413=128]` (first data member of the
`ath_hal_malloc`-allocated `struct ar5413State`, ar5413.c:35-57,777; bound
constant ah_eeprom_v3.h:282; sink `pPDADCValues = ahp->ah_pcdacTable`
ar5413.c:554,793-794). Three unbounded write sites: :497 (extrapolate below),
:506 (main walk), :520 (extrapolate above). Bounded inputs from the EEPROM
parser: numVpd ∈ {0,4,5} (ah_eeprom_v3.c:656-673), pwr_t4 ∈ [0,244]
(pwr_I 5-bit ×4 + 3-4 deltas ×2×15, ah_eeprom_v3.c:715-721), overlap ≤ 15
(AR_PHY_TPCRG5_PD_GAIN_OVERLAP = 0xF, ar5212phy.h:349), boundaries clamped
≤ 63 (ar5413.c:477-482). Worst-case total ≈ 168 (constructed in harness; upper
bound analysis ≈ 15+4·2·15+63+... ≈ 231) > 128 → overflow.

## Reproduction (guest, DragonFly 6.5-DEVELOPMENT x86_64, gcc 8.3)
Harness compiles the REAL function bodies verbatim — build.sh `sed -n
'288,540p' /usr/src/sys/.../ar5413.c` — against a faithful struct
(member order from ar5413.c:35-57; bank row counts 1/1/1/37/3 counted from the
shipped ar5212.ini; verified offsets: pcdacTable@72, Bank1Data@328,
vpdTable_I@1524, sizeof=2040). Dataset crafted in the exact shape
`ar2413SetupRawDataset`/`ar2413EepromToRawDataset` produce for xpd_mask=0xF,
single pier, Pmin pattern {0,58,58,58}, overlap 15, spans ≥2:

```
mode=1 numPdGainsUsed(ret)=4
DF-4619 REPRODUCED: ... first clobbered u16 cell 0 bytes past array end,
  last 79 bytes past (value 0x007f)
```

i.e. 40 uint16 cells (80 bytes) beyond `pcdacTable[127]` were written by the
kernel code, landing in `Bank1Data..Bank6Data`. This is an intra-object
overflow: it stays inside the 2040-byte `ar5413State` allocation (banks occupy
offsets 328-500; ~1.5KB of vpd tables follow), so it does NOT cross the slab —
it corrupts the RF bank scratch buffers later programmed to hardware
(ar5413.c:249-253) and the vpd tables. By C semantics it is an out-of-bounds
write (CWE-787); by kernel impact it is object-state corruption (garbage radio
programming) rather than adjacent-object smashing.

## uid=0?
No. Exploitation is gated on supplying an AR5413 card with crafted EEPROM
(physical access / supply chain); even then the write is intra-object with
constrained 16-bit values (clamped pdadc range 0..127 at two of three sites;
:506 propagates VpdTable_I values ≤ ~0x3FF-derived). The realistic ceiling is
malfunction/panic, not control-flow hijack on this guest's hardware (absent).
Impact recorded as dos.

## Fix validation
`fix.diff` adds `&& kk < PWR_TABLE_SIZE_2413` to the three write loops.
Baseline (pristine /usr/src copy): reproduced as above.
Patched (pristine + all three batch fixes applied, re-extracted, rebuilt):
`DF-4619: NO overflow detected` — bank canary region 0xAAAAAAAA intact,
exit=1 from the "no overflow" detector (expected). See fix_run.log.

## Negative results established while hunting (pass 2)
- vpdTable_L/R/I ROW overflow (span > 64) is IMPOSSIBLE: Pmin_t2 =
  min(first_L,first_R)/2 and Pmax_t2 = min(last_L,last_R)/2 (ar5413.c:435-445)
  while each channel's pwr_t4 list is non-decreasing (deltas ≥ 0, 4-bit,
  ah_eeprom_v3.c:719) and Σdeltas ≤ 4·15 → span ≤ 60 < 64 = row width. The
  `<=` off-by-one at :353 tops out at index 60. KILLED.
- numVpd > 5 OOB: parser hardcodes {0,4,5} (ah_eeprom_v3.c:660-671). KILLED.
- ar5413GetChannelMaxMinPower OOB: the freq > data[numChannels-1] pre-check
  (:716-727) pins the interpolation loop (:730) to i ≤ numChannels-1. KILLED.
- ar5413SetChannel freq underflow (freq<2192): unreachable via the net80211
  channel table; results masked to 8 bits before register writes. KILLED.
- interpolate_signed div-by-zero guarded (:384). ar5413GetRfBank default NULL
  handled. GetMinPower/GetMaxPower pwr_t4[numVpd-1] in-bounds ({0,4,5}).
- DF-1766 (numChannels==0 guard) — known pass-1 finding, not re-reported.

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