ath_intr TDMA/SWBA branch: unchecked TAILQ_FIRST(&ic->ic_vaps) and NULL vap->iv_tdma dereference in hard interrupt context (sc_tdma outlives the TDMA vap)
Summary
On HAL_INT_SWBA with sc_tdma set, ath_intr takes TAILQ_FIRST(&ic->ic_vaps) with no NULL check, passes it to ath_tdma_beacon_send, then evaluates vap->iv_tdma->tdma_bintval. iv_tdma is allocated only for TDMA vaps and is NULL for every other vap type. sc_tdma is cleared in ath_vap_delete only when sc_nvaps==0, so destroying the TDMA vap while a sibling vap remains leaves sc_tdma=1 with a NULL-iv_tdma vap at the list head - the next SWBA NULL-derefs in hard interrupt context. Entry requires admin-level vap create/destroy ordering (create TDMA vap + sibling vap, destroy TDMA vap, wait <= one beacon interval) - deterministic, no timing luck; a teardown race variant needs SMP timing during any vap destroy. Not runnable on the guest (no ath NIC - SWBA can never be raised).
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-3617 Β· 6 files| File | Type | Description | Size | |
|---|---|---|---|---|
| README.md | β | 2.8 KB | β raw | |
| VERDICT.md | β | 2.5 KB | β raw | |
| env.txt | β | 388 B | view raw | |
| fix.diff | β | 1.0 KB | view raw | |
| manifest.json | β | 1.2 KB | view raw | |
| verdict.json | β | 2.4 KB | view raw |
DF-3617 β ath_intr TDMA/SWBA path: unchecked TAILQ_FIRST(&ic->ic_vaps) and iv_tdma NULL-deref
The defect
sys/dev/netif/ath/ath/if_ath.c:2182-2193 (ath_intr, HAL_INT_SWBA):
if (sc->sc_tdma) {
if (sc->sc_tdmaswba == 0) {
struct ieee80211com *ic = &sc->sc_ic;
struct ieee80211vap *vap =
TAILQ_FIRST(&ic->ic_vaps);
ath_tdma_beacon_send(sc, vap); /* derefs vap */
sc->sc_tdmaswba =
vap->iv_tdma->tdma_bintval; /* derefs iv_tdma */
Two unguarded dereferences on the hard-interrupt path:
-
TAILQ_FIRST(&ic->ic_vaps)may be NULL β ath_tdma_beacon_send (sys/dev/netif/ath/ath/if_ath_tdma.c:615) immediately dereferences the vap (avp->av_bcbufvia ATH_VAP(vap)) β NULL-deref panic in hard interrupt context. -
vap->iv_tdmamay be NULL for a non-TDMA vap β iv_tdma is allocated ONLY in ieee80211_tdma_vattach (sys/netproto/802_11/wlan/ieee80211_tdma.c:197) and is NULL for every other vap type βNULL->tdma_bintvalpanic.
Reachability paths
(a) Config-ordering (not even a narrow race): sc->sc_tdma is cleared
in ath_vap_delete only when sc->sc_nvaps == 0 (if_ath.c:1855-1858). If
the TDMA vap is destroyed while any other vap still exists, sc_tdma stays
set while the vaps list now heads with a non-TDMA vap (or the remaining vap
is itself deleted later leaving the list momentarily empty) β the next SWBA
interrupt takes the TDMA branch and dereferences either NULL iv_tdma or a
NULL vap.
(b) Teardown race: ath_vap_delete disables interrupts at
if_ath.c:1785 (ath_hal_intrset(ah, 0)), but an ath_intr already past
ath_hal_intrpend (if_ath.c:2090) on another CPU keeps executing; the SWBA
handling at 2175+ runs after the PCU lock was dropped at 2163, so nothing
serializes it against ieee80211_vap_detach emptying ic_vaps (1793) or
against sc_tdma = 0 (1855). Window is milliseconds wide (TXQ drains),
not microseconds.
Preconditions
Atheros NIC with TDMA-capable HAL (mac version > 0x78, if_ath.c:1028), IEEE80211_SUPPORT_TDMA built, a TDMA (AHDEMO+CLONE_TDMA) vap created, and either the vap-deletion ordering above or the teardown race. All vap create/destroy operations require admin (ifconfig); the panic itself then fires from interrupt context.
Why inconclusive here
The audit guest has no Atheros hardware (env.txt): SWBA interrupts cannot be generated, so neither the config-ordering path nor the race can be executed. Source-level certainty is the bar for this file; the dereferences and the flag-lifetime defect are proven above from the cited lines.
Fix
fix.diff guards both dereferences in the ISR (minimal, safe in hard interrupt context) β see VERDICT.md for the companion sc_tdma lifetime note.
DF-3617 β VERDICT
Status: inconclusive (NULL-deref/panic class defect proven from source; cannot execute on a guest with no Atheros NIC)
Reproduced?
No. The defect fires from ath_intr() on HAL_INT_SWBA, which requires the
wireless hardware to raise a software-beacon-alert interrupt. The guest has
no ath device (env.txt: no ath PCI id, no dev.ath sysctl, if_ath.ko present
but unloaded), so no SWBA can ever arrive. No amount of userland
construction on this guest reaches the code.
Why the defect is certain anyway
- The dereferences are unconditional in the TDMA SWBA branch
(if_ath.c:2186-2190):
TAILQ_FIRST(&ic->ic_vaps)result passed straight intoath_tdma_beacon_send()(which dereferencesATH_VAP(vap)βavp->av_bcbuf, if_ath_tdma.c:615ff) and thenvap->iv_tdma->tdma_bintval. iv_tdmais non-NULL only for TDMA vaps (sys/netproto/802_11/wlan/ieee80211_tdma.c:197 sets it in ieee80211_tdma_vattach; :211 clears it at detach; every other vap type leaves it NULL).sc->sc_tdmaoutlives the TDMA vap: ath_vap_delete clears it only whensc->sc_nvaps == 0(if_ath.c:1855-1858). Delete the TDMA vap while any sibling vap remains β sc_tdma==1 with a non-TDMA (iv_tdma==NULL) vap at the head of ic_vaps β guaranteed NULL deref on the next SWBA. This path needs no timing luck, only vap create/destroy ordering (admin-triggered; result is a kernel panic β local DoS).- The teardown-race variant: ath_hal_intrset(ah,0) at if_ath.c:1785 does not stop an ISR already executing; SWBA processing at 2175+ holds no lock that ieee80211_vap_detach (1793) or sc_tdma=0 (1855) respects.
Impact
NULL-deref panic in hard interrupt context (kernel DoS). Not memory corruption (no wild write), no info leak. Requires admin-level vap reconfiguration on a TDMA-configured ath interface to reach β hence Low.
Fix
fix.diff: guard vap == NULL || vap->iv_tdma == NULL in the SWBA TDMA
branch (skip the beacon send, leave sc_tdmaswba at 0 so the next SWBA
retries). Companion (recommended, not in the minimal diff): clear sc_tdma
when the last TDMA vap is destroyed rather than when sc_nvaps hits 0 β
track it at if_ath.c:1840-1859 alongside sc_nstavaps.
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
not_testablefix.diff adds ISR-side guards; applies clean via git apply --check but no ath hardware exists to run baseline/patched comparison
findings/poc/DF-3617/fix.diff
Confirmed kernel references
Detail
Evidence (decisive lines)
README.md/VERDICT.md line-cited traces; env.txt (no ath hardware); fix.diff applies clean (git apply --check)
PoC changes
n/a - no seeded PoC; analysis-only pack (hardware-interrupt path, no HW on guest)
Verified recommended fix
Guard vap==NULL/iv_tdma==NULL in the SWBA TDMA branch and clear sc_tdma on last TDMA vap destruction
Verdict
ath_intr's HAL_INT_SWBA TDMA branch (if_ath.c:2186-2190) passes TAILQ_FIRST(&ic->ic_vaps) unchecked into ath_tdma_beacon_send (which dereferences ATH_VAP(vap)->av_bcbuf) and then dereferences vap->iv_tdma->tdma_bintval. iv_tdma is NULL for every non-TDMA vap (wlan/ieee80211_tdma.c:197 allocates it only for TDMA vaps). sc_tdma is cleared only when sc_nvaps==0 (if_ath.c:1855-1858), so destroying the TDMA vap while a sibling vap remains leaves sc_tdma=1 with a NULL-iv_tdma vap at the list head: the next SWBA interrupt NULL-derefs in hard interrupt context (deterministic given the vap ordering; no timing luck needed). A teardown race variant also exists (an ISR already past ath_hal_intrpend at 2090 keeps running after ath_hal_intrset(ah,0) at 1785; SWBA processing holds no lock that vap detach respects). Not executable on the audit guest: no Atheros NIC means no SWBA can ever be raised (env.txt). Impact class: kernel panic / local DoS requiring admin-level TDMA vap reconfiguration.
No comments yet.