# DF-3615 — unvalidated ts_antenna indexes ast_ant_tx[8]/sc_ant_tx[8] (latent OOB write)

## What the finding is
`ath_tx_update_stats()` (sys/dev/netif/ath/ath/if_ath.c:4196-4199) does:

```c
if (ts->ts_status == 0) {
        u_int8_t txant = ts->ts_antenna;
        sc->sc_stats.ast_ant_tx[txant]++;   /* ast_ant_tx[8] */
        sc->sc_ant_tx[txant]++;             /* sc_ant_tx[8]  */
```

`ts->ts_antenna` is a raw `uint8_t` from the HAL TX-status descriptor
(sys/dev/netif/ath/ath_hal/ah_desc.h:56, comment: "may not be valid for all
h/w"). No clamp. The RX twin of this exact code CLAMPS the same-class field
(sys/dev/netif/ath/ath/if_ath_rx.c:828-835) because "Some users w/ AR9285
NICs have reported crashes here because rs_antenna field is bogusly large"
(upstream field-reported crashes, fixed by clamping at the driver).

## Current triggerability (why this is latent, not live)
Every HAL in this tree writes a bounded value into ts_antenna:
- ar5210_xmit.c:614  -> 0 ("NB: don't know")
- ar5211_xmit.c:645  -> 0
- ar5212_xmit.c:943  -> 1 or 2
- ar5416_xmit.c:814  -> 0 ("don't switch antennas on Owl")
- contrib ar9300_xmit_ds.c:354 -> 0
So no in-tree configuration can emit antenna>7 **today**; the bug fires the
day a HAL (or a HAL bug) forwards a raw descriptor byte — exactly the AR9285
RX-side failure mode this driver family already shipped to users.

## Measured corruption geometry (guest evidence)
See offsets_dmesg.txt (produced by offmod.c / build.sh / run.log on the
audit guest, DragonFly 6.5-DEVELOPMENT X86_64_GENERIC):

  sizeof(ath_softc)      = 13392
  sc_stats.ast_ant_tx    = 7820   (array [8] ends 7852)
  sc_rx methods (fn ptrs)= 8552   -> index (8552-7820)/4  = 183
  sc_tx methods (fn ptrs)= 8736   -> index (8736-7820)/4  = 229
  sc_txedma              = 8784
  sc_ant_tx              = 12832  (array [8] ends 12864)
  sc_cabq (pointer)      = 12864  -> index 8 EXACTLY (first OOB slot)
  sc_bslot[] (vap ptrs)  = 13040  -> indices 52..59
  sc_cal_ch (callout)    = 13080  -> index 62
  sc_eepromdata (ptr)    = 13168
  end of object          = 13392  -> indices >140 run PAST the softc heap alloc

Consequences if a value >7 ever flows in:
- `ast_ant_tx[txant]++` with 183<=txant<=246 increments the sc_rx/sc_tx
  method-table function pointers (wild indirect call on next dispatch).
- `sc_ant_tx[txant]++` with txant==8 increments the sc_cabq pointer itself
  (dereferenced as sc->sc_cabq->axq_qnum in ath_tx_proc_q0/q0123).
- txant>140 writes past the end of the 13392-byte softc allocation into
  adjacent kernel heap (increment primitive, +1 per TX completion —
  high-frequency, remotely-driven cadence).

## Build / run (offset measurement only — no ath hardware needed)
    ./build.sh          # builds off.ko against the X86_64_GENERIC obj tree
    kldload ./off.ko ; dmesg | grep OFF ; kldunload off

## Expected output
The OFF lines in offsets_dmesg.txt / run.log.

## Why the corruption itself is not reproduced here
The audit guest has no Atheros NIC (see env.txt: no ath PCI device, no
dev.ath sysctl, if_ath.ko present in /boot/kernel but unloaded). The
corrupting write sits on the TX-completion interrupt path, which cannot run
without the hardware; and with the in-tree HALs ts_antenna never exceeds 2.
Honest verdict: **inconclusive** — defect is source-certain, execution is
not possible on this guest.
