# DF-5092 VERDICT — ar5416GpioCfgInput drives instead of tristating

**Status: untested** (no reproduction path in the audit guest — hardware-only
code path; Info-class finding, Phase V verification not mandated).
**Impact: none** at the kernel-memory level; hardware-functional defect
(input pins actively driven), root-gated, upstream-inherited.

## Root cause, line-accurate

- `sys/dev/netif/ath/ath_hal/ar5416/ar5416_gpio.c:146` — comment states the
  intent: "If configured as input, set output to tristate".
- `sys/dev/netif/ath/ath_hal/ar5416/ar5416_gpio.c:150-151` — code clears the
  2-bit drive field then immediately sets it to `AR_GPIO_OE_OUT_DRV_ALL`
  (0x3 = "drive always"), the opposite of tristate.
- `sys/dev/netif/ath/ath_hal/ar5416/ar5416reg.h:570-574` — `AR_GPIO_OE_OUT_DRV_NO`
  (0x0, "tristate") is the correct value; it is what the clear-only sequence
  would leave in place if line 151 did not exist.
- Twin implementations that do it correctly:
  `ar5212_gpio.c:57-66` (CR_N = no drive), `ar5211_misc.c:213-225` (CR_N).
- Consumers that pass *externally driven* pins:
  `ar5416_btcoex.c:355-356` and `ar5416_btcoex.c:388` (BT sense inputs),
  `ar5416_btcoex.c:237` (WLAN active pin released on btcoex disable).
- Upstream provenance: DragonFly's file has a single import commit
  (6cc80ee9); the file is byte-identical to FreeBSD CURRENT
  sys/dev/ath/ath_hal/ar5416/ar5416_gpio.c (fetched 2026-09-27), including
  this bug → inherited, fix owner upstream.

## Why not verified on the guest

- ar5416 GPIO functions are only reachable after an Atheros PCI/PCIe device
  attaches and `ath_hal_attach()` succeeds; they program device MMIO
  (AR_GPIO_OE_OUT @ 0x404c). The QEMU/KVM audit guest emulates no Atheros
  NIC: `dfbsd-qemu/boot.log` has zero ath(4)/Atheros probe lines (single
  "ath" substring is an ldconfig path). `ath_hal` is compiled into GENERIC
  (sys/config/X86_64_GENERIC:263-266) but never executes.
- Not a memory-corruption/privesc/hammer2 finding and not a trivial local
  PoC (requires physical combo-NIC hardware + oscilloscope or register
  probe) → Phase V skip criteria apply; recorded as `untested` per the
  batch's status enumeration (no `skipped` value allowed).

## Pass-2 negatives for this file (checked and killed, not re-reported)

- DF-2098 (gpio index unvalidated in CfgOutput/CfgInput/Set/SetIntr,
  HALASSERT is `#define HALASSERT(_x)` no-op without AH_ASSERT —
  ah_internal.h:665-676) — known, NOT re-reported. Consumers verified:
  `if_ath_sysctl.c:210-221` (`hw.ath.N.ledpin`, RW, unbounded, root-only)
  flows into `ath_led_config()` (`if_ath_led.c:128`) → confirms the DF-2098
  attack chain is root-gated only.
- DF-2099 (missing `else` at ar5416_gpio.c:192-194 overwrites the AR9287
  value with the pre-9280 `AR_GPIO_IN_VAL` extraction on KIWI) — known, NOT
  re-reported. (Also present in FreeBSD CURRENT, byte-identical.)
- `ar5416GpioSetIntr` (ar5416_gpio.c:207-278): **dead code in this tree** —
  the sole reference is the `ath_hal_gpioSetIntr` macro
  (ah_internal.h:452-453); no caller exists in `sys/dev/netif/ath/ath/*.c`.
  Residual quirks there (pin-13 polarity silently dropped because
  AR_GPIO_INTR_POL_VAL is 0x1FFF = 13 bits while AR5416 advertises 14 pins
  (ar5416_attach.c:985); RMW of W1C AR_INTR_SYNC_CAUSE re-clearing all
  pending GPIO bits, ar5416_gpio.c:238-241) are therefore unreachable.
- In-range shifts are safe: halNumGpioPins = 14/10/12/10
  (ar5416_attach.c:985, ar9280_attach.c:882, ar9285_attach.c:529,
  ar9287_attach.c:435) → gpio ≤ 13 → `1 << gpio` ≤ bit 13; the intr-enable
  fields (0xFFFC0000, S=18) hold 14 bits; `gpio % 6) * 5` ≤ 25 in
  cfgOutputMux. UB shifts need an out-of-range index = DF-2098.
- `cfgOutputMux` MUX1 readback WAR (lines 67-77) matches the documented
  Owl/Pre-Merlin2 PRDATA quirk; verified identical upstream; no new defect.
- RMW races on AR_GPIO_IN_OUT / AR_GPIO_OE_OUT between the LED callout
  (if_ath_led.c:171,182) and config ioctls: lost-update LED glitch at
  worst; no memory-safety consequence.

## Fix

One-line deletion (leaves the cleared field = DRV_NO = tristate), matching
the ar5210/5211/5212 semantics and the function's own comment — see
`fix.diff`. Should be upstreamed to FreeBSD (same bug there).

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