# DF-4850 — VERDICT

* **status:** untested
* **reproduced:** 0
* **impact:** none (demonstrated statically; class is logic/correctness with a
  latent second-OOB amplifier for DF-1931 — no memory-safety violation on its
  own)
* **confidence:** certain (code mechanism proven at line level; impact
  characterization from the HAL rate tables in-tree)

## Why untested (not skipped carelessly — it cannot run on the guest)

1. The trigger requires an Atheros NIC. The QEMU guest has none
   (`vm.sh run_user 'pciconf -l | grep ath'` would be empty; ath is not even
   compiled for a NIC-less VM). Every sink is on the ath tx path.
2. amrr is not the default rate-control module: GENERIC selects
   `device ath_rate_sample` (`sys/config/X86_64_GENERIC:266`); amrr requires a
   custom kernel config (`optional ath_rate_amrr`, `sys/conf/files:264-265`),
   and only one of amrr/onoe/sample can be linked at a time (all three define
   the same `ath_rate_*` symbols and `DECLARE_MODULE(ath_rate, ...)` —
   `amrr.c:513`).
3. Fix validation likewise requires the hardware tx path, so
   `fix_status: not_testable`.

## The chain, statically proven

1. `ath_rate_update()` caches **rate codes** in `amrr_node`:
   `amrr.c:247` `amn->amn_tx_rate0 = rt->info[amn->amn_tx_rix0].rateCode`;
   likewise series 1/2 at `amrr.c:258-260, 267-269` and series 3 at
   `amrr.c:275-277` (`rt->info[0].rateCode`).
2. `ath_tx_do_ratelookup()` stores the **correct** series-0 index
   (`if_ath_tx.c:1392` `bfs_rc[0].rix = rix`), then calls
   `ath_rate_getxtxrates()` (`if_ath_tx.c:1396-1398`, gated only on
   `bfs_ismrr && try0 != ATH_TXMAXTRY`).
3. `ath_rate_getxtxrates()` **overwrites** `rc[0].rix` and fills `rc[1..3].rix`
   with the cached rate codes (`amrr.c:135-138`), ignoring its `rix0` parameter
   (`amrr.c:129`). This violates the field contract
   (`if_athrate.h:91` — "ratetable index, not rate code").
4. Sinks dereference `rt->info[rc[i].rix]` unguarded (only `tries == 0` entries
   are skipped, `if_ath_tx_ht.c:251-254`):
   `if_ath_tx_ht.c:254, 260` (every tx dispatch — `if_ath_tx.c:1531, 2298,
   3034, 5525, 5553, 5740`), `if_ath_tx_ht.c:457-458` (A-MPDU pad),
   `if_ath_tx_ht.c:579-580` (11n descriptor series), `if_ath_tx.c:1064, 1128,
   1260, 1282` (RTS/CTS durations).
5. Value domain: amrr maps only legacy dot11 rates (`IEEE80211_RATE_VAL`=0x7f;
   HT rows keyed ≥0x80 in `sc_rixmap`, `if_ath.c:6203-6208`), so codes ≤ 0x1b
   (27) < 64 (`ah.h:681`) → **in-bounds wrong entry**, never standalone OOB.
6. Wrong-entry consequences, from the in-tree tables:
   - `ar5416_11ng_table` (rateCount 28, `ar5416_phy.c:31`): code 0x1b →
     `info[27]` = MCS15/0x8f; code 0x18 → `info[24]` = MCS12/0x8c; HT rows
     trigger `ATH_RC_HT_FLAG`/CW40/SGI/STBC (`if_ath_tx_ht.c:278-317`) on
     legacy-chosen series → frames transmitted at HT rates to legacy peers.
   - `ar5416_11na_table` (rateCount 24): code 0x0b → `info[11]` = MCS3/0x83.
   - `ar5212_11a_table` (rateCount 8): indices 8..27 hit the zero-filled tail
     → `ratecode = 0` in the MRR series.
7. DF-1931 amplification: `sc_rixmap` 0xff sentinel (already filed, this file,
   `amrr.c:246-267`) makes the cached "rate codes" garbage bytes read from
   `rt->info[255]`; step 4 then re-dereferences `rt->info[garbage≤255]` — a
   second OOB read past `info[64]` (~68-190 entries).

## Why severity is Low

* Standalone: no OOB — a wrong in-bounds entry; effect is mis-programmed tx
  rates/flags (availability/interop of the link, remotely influenceable via the
  peer's advertised rate set).
* Requires a non-default kernel config (`ath_rate_amrr`) plus Atheros radio.
* The OOB variant rides on DF-1931's already-known unchecked sentinel.

## Fix validation

Not possible without hardware → `fix_status: not_testable`. The authored
`fix.diff` (indices stored/returned per series, mirroring sample.c) is
compile-checked by inspection only; `sys/` remains untouched per audit rules.

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