# DF-4872 — ar9287Attach: 2GHz-only Kiwi-2 caps never enforced — GMODE divergence re-adds 11A/11NA modes and 5GHz edges survive; enables 5GHz channel selection on 2GHz-only silicon (upstream enabler of the DF-4793 NULL-pier panic)

## What was verified (static, line-by-line; no AR9287 silicon on the audit guest)

The full chain from EEPROM opflag to 5GHz channel admission, every hop cited:

1. **The AR9287 EEPROM layer explicitly denies A-mode.**
   `sys/dev/netif/ath/ath_hal/ah_eeprom_9287.c:73-74`
   ```c
   case AR_EEP_AMODE:
       return HAL_EIO;		/* no 5GHz for Kiwi */
   ```
   The AR9287 EEPROM image itself carries only 2GHz calibration data:
   `ah_eeprom_9287.h:135-153` — `calFreqPier2G[AR9287_NUM_2G_CAL_PIERS]`,
   `calPierData2G[AR9287_MAX_CHAINS][AR9287_NUM_2G_CAL_PIERS]`, and a single
   `modalHeader` ("only 2.4ghz here; so only one modal header entry",
   ah_eeprom_9287.c:187). There is no 5GHz pier/target data anywhere.

2. **The generic caps builder re-adds 11A anyway via the GMODE divergence.**
   `ar9287Attach` → `ar9287FillCapabilityInfo`
   (`sys/dev/netif/ath/ath_hal/ar9002/ar9287_attach.c:321-324, 428-469`)
   calls `ar5416FillCapabilityInfo(ah)` at line 433 and inherits:
   - `ar5416_attach.c:904-915`: when `AR_EEP_GMODE` is set (every functional
     11g card: `v9287EepromGet` returns OK when `opCapFlags &
     AR5416_OPFLAGS_11G`, `ah_eeprom_9287.c:75-79`; identical polarity in
     `ah_eeprom_v14.c:110-115` and `ah_eeprom_v4k.c:83-90`), lines 910-914
     unconditionally OR `HAL_MODE_11A | HAL_MODE_11NA_HT20 |
     HAL_MODE_11NA_HT40PLUS | HAL_MODE_11NA_HT40MINUS` into
     `halWirelessModes` — even though the AMODE branch was denied.
   - `ar5416_attach.c:920-921`: `halLow5GhzChan = 4915;
     halHigh5GhzChan = 6100;` set unconditionally.

3. **ar9287FillCapabilityInfo never clamps.** Its override block
   (`ar9287_attach.c:435-466`) sets ~20 fields (GPIO count, WoW, RIFS, STBC,
   SGI20, ...) but never touches `halWirelessModes`, `halLow5GhzChan`, or
   `halHigh5GhzChan`. Unlike the ar9285 twin (DF-4799), nf_5g *is* populated
   here (`ar9287_attach.c:353-355`), so the residual defect for the AR9287
   is exactly the caps/edges divergence.

4. **halWirelessModes is the channel-admission gate.**
   `if_ath.c:6073-6084` `ath_getradiocaps()` → `ath_hal_getchannels(...,
   HAL_MODE_ALL, ...)`. In `getchannels()`
   (`sys/dev/netif/ath/ath_hal/ah_regdomain.c:398-416`):
   ```c
   modesAvail = ath_hal_getWirelessModes(ah);   /* == halWirelessModes */
   ...
   if ((cm->mode & modeSelect) == 0) continue;   /* HAL_MODE_ALL passes */
   if ((cm->mode & modesAvail) == 0) continue;   /* <-- the only HW gate */
   ```
   With the divergent 11A/11NA bits set, every 5GHz `cmode` passes; the 5GHz
   channel bitmap then comes from the EEPROM regdomain
   (`ah_currentRD = regDmn[0]`, `ar9287_attach.c:334-335`, unvalidated u16).
   `ar5212GetChannelEdges` (`ar5212_attach.c:646-655`) hardcodes 4915/6100
   for any 5GHZ-flagged mode, so 5GHz bands are admitted.

5. **Downstream consequence (already filed at the crash site as DF-4793).**
   Selecting one of those 5GHz channels reaches
   `ar9287SetPowerCalTable` (`ar9002/ar9287_reset.c`): the 9287 EEPROM
   accessors return a NULL pier list for non-2GHz channels, and the
   unguarded per-chain walk NULL-derefs `pList[0]` in
   `ath_ee_getLowerUpperIndex` → kernel panic. Even without the panic, the
   radio is programmed from 2GHz-only calibration data (regulatory
   misoperation), mirroring DF-4799's impact analysis for the AR9285.

## Why no runtime PoC (untested, per family precedent DF-4793/DF-4799/DF-4548)

The trigger requires an AR9287 ("Kite-2") PCIe NIC whose EEPROM carries an
11G opflag (normal) plus a regdomain with 5GHz entries. The single-tenant
QEMU/KVM audit guest has no Atheros NIC (no PCIe device assignment), so
neither the panic nor the mis-tune can be exercised there. Verification is
the static chain above; every hop was opened and read, no hop is assumed.

## Threat model

Untrusted-EEPROM (same model as DF-4548/DF-4793/DF-4799): a card with a
reprogrammed/corrupt EEPROM (physical access, resold hardware, or a
malicious "compat" card). No EEPROM validation happens between the raw
image and `regDmn[0]`/`opCapFlags` beyond the checksum, which the attacker
recomputes. Note the GMODE hop needs nothing unusual at all — every stock
11g AR9287 satisfies it; only the regdomain content decides whether 5GHz
channels appear.

## Fix

Mask the A-family modes and invalidate the 5GHz edges in
`ar9287FillCapabilityInfo` right after the inherit (see `fix.diff`). The
cleaner companion fix is in `ar5416_attach.c:904-915` — the GMODE block
should not OR 11A/11NA bits; every 5416-family chip that supports 11A
already gets those bits from the AMODE branch — but the per-chip clamp is
the minimal, targeted change (matches the fix proposed for DF-4799).

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