ar5210ResetTxQueue dereferences ah_curchan (IEEE80211_IS_CHAN_TURBO) without the NULL guard both sibling HALs carry ("NB: chan can be NULL during attach")
Summary
The queue reset caches ah_curchan and dereferences it unconditionally for every DATA-queue reset - ah_curchan is NULL from attach until the first Reset. Both ar5211 and ar5212 guard exactly this with an attach-time comment; the 5210 missed it and its chan use is broader (the whole turbo/normal IFS branch). In-tree call order protects; latent NULL-deref for pre-channel-set resets. One-line-guard fix (build+boot validated).
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-4734 Β· 8 files| File | Type | Description | Size | |
|---|---|---|---|---|
| README.md | β | 2.3 KB | β raw | |
| VERDICT.md | β | 2.2 KB | β raw | |
| fix.diff | β | 545 B | view raw | |
| build.sh | β | 143 B | view raw | |
| build.log | β | 5.1 MB | β download | |
| env.txt | β | 674 B | view raw | |
| manifest.json | β | 1.1 KB | view raw | |
| verdict.json | β | 3.0 KB | view raw |
DF-4734 β ar5210ResetTxQueue dereferences ah_curchan without the NULL guard both siblings carry
File: sys/dev/netif/ath/ath_hal/ar5210/ar5210_xmit.c:157,180
Severity: Low (latent NULL-deref panic; in-tree call order protects) β certain on the divergence.
Root cause
ar5210ResetTxQueue takes the current channel
157: const struct ieee80211_channel *chan = AH_PRIVATE(ah)->ah_curchan;
and, for every DATA queue, dereferences it unconditionally:
180: if (IEEE80211_IS_CHAN_TURBO(chan)) {
IEEE80211_IS_CHAN_TURBO(_c) is ((_c)->ic_flags & IEEE80211_CHAN_TURBO) != 0
(sys/netproto/802_11/_ieee80211.h:268) β a plain deref. ah_curchan is AH_NULL
from attach until the first ar5210Reset runs.
Both sibling HALs guard exactly this and annotate why:
ar5211_xmit.c(ar5211ResetTxQueue):/* NB: chan can be NULL during attach */followed byif (chan && IEEE80211_IS_CHAN_B(chan))β chan used nowhere else.ar5212_xmit.c(ar5212ResetTxQueue): identical guard, identical comment.
The 5210 HAL missed the guard, and unlike its siblings it uses chan for the whole
IFS programming branch (turbo vs normal), so the deref executes on every DATA
resetTxQueue call with a NULL channel.
Reachability (why latent)
In-tree order: ath_attach runs ath_hal_reset (sets ah_curchan) before
ath_txq_setup calls ath_hal_resettxqueue (if_ath.c:4125-4130), and the only other
caller (ath_txq_update) runs after channel changes. So no in-tree path reaches the
deref with chan == AH_NULL; a driver variant (or future caller) that sets up/resets
a DATA queue before the first channel reset takes a NULL-deref kernel panic. Same
"latent, caller-order-protected" class as the DF-4519/4712/4733 family.
Reproduce
Hardware-gated (no Atheros NIC on the guest). Source-confirmed divergence plus fix build-validation:
scp fix.diff guest:/tmp/df4734.diff vm.sh run_root 'cd /usr/src && patch -p1 < /tmp/df4734.diff && make nativekernel KERNCONF=X86_64_GENERIC' # expected: BUILD_RC=0, ar5210_xmit.c compiled -Werror (build.log)
Fix
fix.diff: if (chan != AH_NULL && IEEE80211_IS_CHAN_TURBO(chan)) with the siblings'
comment β NULL channel takes the normal-mode defaults, matching ar5211/ar5212 semantics
(they fall back to INIT_CWMIN when chan is NULL).
VERDICT β DF-4734
Finding
ar5210ResetTxQueue caches AH_PRIVATE(ah)->ah_curchan (ar5210_xmit.c:157) and
dereferences it unconditionally in IEEE80211_IS_CHAN_TURBO(chan) (line 180) for every
DATA-queue reset. IEEE80211_IS_CHAN_TURBO is a raw (_c)->ic_flags deref
(sys/netproto/802_11/_ieee80211.h:268). ah_curchan is NULL from attach until the
first ar5210Reset. Both sibling HALs carry an explicit guard with the comment
"NB: chan can be NULL during attach" and use chan nowhere unguarded:
- ar5211_xmit.c ar5211ResetTxQueue:
if (chan && IEEE80211_IS_CHAN_B(chan)) - ar5212_xmit.c ar5212ResetTxQueue:
if (chan && IEEE80211_IS_CHAN_B(chan))
(verified by extracting both functions β chan appears only inside the guard). The 5210
HAL missed it, and its usage is broader (the whole turbo/normal IFS programming
branch), so a DATA resetTxQueue before the first channel reset is a NULL-deref
kernel panic.
Reachability (latent)
In-tree call order protects: ath_attach performs ath_hal_reset (which sets
ah_curchan) before ath_txq_setup β ath_hal_resettxqueue (if_ath.c:4125-4130); the
other caller (ath_txq_update) runs on channel changes. No in-tree path reaches the
deref with NULL. Same caller-order-protected latent class as DF-4519/4712/4733.
Hardware-gated on the guest (no Atheros NIC, verified).
Verification
- Runtime: not possible on the guest (no ar5210 hardware; the HAL is inert).
- Fix build-validated:
fix.diff(chan != AH_NULL &&+ sibling comment) applied to guest /usr/src; singlemake nativekernel KERNCONF=X86_64_GENERICbuild together with DF-4733/DF-4735: BUILD_RC=0, -Werror, ar5210_xmit.c compiled (build.log).
Bottom line
Certain, precisely-scoped cross-version divergence (both siblings guard + annotate; 5210 forgot). Low severity latent NULL-deref panic; one-line fix mirroring siblings, build-validated.
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.
Fix verification
fixedbuild-only validation (runtime hardware-gated): fix.diff applied; nativekernel BUILD_RC=0 -Werror (build.log:7129 ar5210_xmit.c); kernel installed and booted clean. NULL-chan path not exercisable on the guest (no ath hardware).
findings/poc/DF-4734/build.log (RC=0; ar5210_xmit.c -Werror at :7129); fix.diff
Confirmed kernel references
Detail
Exploit chain
[]
Evidence (decisive lines)
findings/poc/DF-4734/VERDICT.md (divergence proof: sibling guards quoted); build.log (RC=0; ar5210_xmit.c -Werror at :7129); fix.diff (one-line NULL guard mirroring siblings); env.txt
PoC changes
n/a (no runtime PoC attempted; hardware-gated per DF-4519/DF-4712 protocol)
Verified recommended fix
Guard the deref: 'if (chan != AH_NULL && IEEE80211_IS_CHAN_TURBO(chan))' - one line mirroring the ar5211/ar5212 NULL-chan guards.
Verdict
untested (runtime): ar5210ResetTxQueue caches AH_PRIVATE(ah)->ah_curchan (ar5210_xmit.c:157) and dereferences it unconditionally in IEEE80211_IS_CHAN_TURBO(chan) (:180; macro is a raw ->ic_flags deref, _ieee80211.h:268). ah_curchan is NULL from attach until the first ar5210Reset. Both sibling HALs guard exactly this with 'if (chan && ...)' and the comment 'NB: chan can be NULL during attach' (ar5211_xmit.c ar5211ResetTxQueue; ar5212_xmit.c ar5212ResetTxQueue - verified: chan appears only inside the guard in both); ar5210 missed it and its usage is broader (the whole turbo/normal IFS branch). In-tree call order protects (ath_attach resets before ath_txq_setup, if_ath.c:4125-4130) - latent. No Atheros NIC on the guest, runtime not observable. Fix build-validated: nativekernel BUILD_RC=0 -Werror (build.log:7129), kernel installed and booted clean.
No comments yet.