# DF-4661 — VERDICT

**REPRODUCED** (impact: dos — wild KVA reads + uninitialized stack read; hardware-gated trigger)

## Method

Same verbatim-extraction harness as DF-4660 (real ar2413.c:245-496 function
bodies from the guest's pristine /usr/src, faithful struct ar2413State).

Mode 2 crafts the EEPROM-shaped zero-gain dataset: xpd_mask=0 ⇒ every
numVpd=0 — exactly what `ar2413SetupRawDataset` produces for such an EEPROM
(ah_eeprom_v3.c:656-673) ⇒ numPdGainsUsed==0.

## Result (run.log; variance across runs in the "repeat" section)

1. **Wild reads at +0x1FFFFFFFE bytes.** To emulate the kernel direct map
   (where a +8.59 GB offset still hits mapped RAM), the harness mmaps the
   exact wild pages and seeds 0x5A5A:
   * `pPdGainBoundaries[ii-1]` at ar2413.c:484 with ii==0 (uint32_t) ⇒
     element 0xFFFFFFFF ⇒ read at `gb+0x1FFFFFFFE` — value **0x5A5A**
     observed propagating into `gainBoundaries[0]`, which
     `ar2413SetPowerTable` writes to `AR_PHY_TPCRG5` (ar2413.c:595-600);
   * `pPDADCValues[kk-1]` at ar2413.c:488 with kk==0 ⇒ read at
     `pcdacTable+0x1FFFFFFFE` — **0x5A5A** propagates into
     `pcdacTable[0]` and is replicated across the whole pdadc table →
     32 PHY register writes (ar2413.c:586-593).
   The identical uint32-wrap arithmetic is separately proven to fault in
   mode 3 (SIGSEGV si_addr == expected wild address, DF-4662 pack): in the
   kernel the same wrap lands in the direct map (garbage radio programming)
   or a KVA hole (panic on every channel change).
2. **Uninitialized stack read.** `*pMinCalPower = Pmin_t2[0]`
   (ar2413.c:424) with Pmin_t2[] never written: minPower varies run-to-run
   (0xd2e0 / 0xd3b0 / 0xd620 / 0xd370) — flows into
   `ah_txPowerIndexOffset` (ar2413.c:579-582).
3. The `HALASSERT(1 <= numPdGainsUsed && numPdGainsUsed <= 3)` at
   ar2413.c:536 is a no-op in release builds (AH_ASSERT undefined,
   ah_internal.h:665-676), and the caller (ar2413.c:533-535) ignores the
   count's zero-ness; `switch (numPdGainsUsed)` then matches no case
   (`SM(numPdGainsUsed-1, …)` writes a wrapped -1 to the register mask).

## Exploitation ceiling

Crafted EEPROM on AR2413 hardware (physical/supply-chain). Wild kernel read
→ panic (KVA hole) or garbage radio programming; uninit stack byte-pair
feeds a hardware offset. No exfil to userspace, no uid0 route.

## Fix validation (fix_run.log)

fix.diff: early `return 0` when numPdGainsUsed==0 before the Pmin_t2[0]
read (ar2413.c:424) + caller-side `if (numPdGainsUsed == 0) return AH_FALSE;`
in ar2413SetPowerTable. Patched harness mode 2: ret=0, minPower keeps the
0x7c7c sentinel (no uninit read), no 0x5A5A propagation. git-apply verified.

## NOT re-reported

DF-1796 (numChannels==0, pass 1) and DF-4662 (flat-curve wrap — same
uint32-underflow class, different trigger/guard) are distinct findings.

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