ar5211_xmit: signed q<0 bypasses the >=-only checks in ar5211Set/GetTxQueueProps down to &ah_txq[q], and five exported xmit ops gate q only via inert HALASSERT (ar5211 analogue of DF-4519)
Summary
Set/GetTxQueueProps take signed q and check only >=, so negative q reaches &ah_txq[q] - setTxQProps reads tqi_type then writes ~15 fields below the array; the five tx ops gate q only via the production-no-op HALASSERT, leaving AR_QTXDP(q) OOB MMIO and 1<<q UB unvalidated. Latent (all in-tree callers pass validated 0..9); same class as verified DF-4519 (ar5212). Hardware-gated on guest. Mirror-DF-4519 fix, build-validated on guest (-Werror).
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-4712 Β· 8 files| File | Type | Description | Size | |
|---|---|---|---|---|
| README.md | β | 1.4 KB | β raw | |
| VERDICT.md | β | 5.9 KB | β raw | |
| fix.diff | β | 2.3 KB | view raw | |
| build.log | β | 5.1 MB | β download | |
| env.txt | β | 856 B | view raw | |
| manifest.json | β | 1.6 KB | view raw | |
| verdict.json | β | 4.1 KB | view raw | |
| build.sh | β | 154 B | view raw |
DF-4712 β ar5211 HAL xmit ops: signed/negative tx-queue index reaches ah_txq[q] and unchecked MMIO (ar5211 analogue of DF-4519)
File: sys/dev/netif/ath/ath_hal/ar5211/ar5211_xmit.c (pass 2, GLM 5.3)
Severity: Low (latent β no unprivileged trigger today) Β· Confidence: certain (code pattern) Β· Bucket: base:net
Build / Run
This finding is hardware-gated (requires an Atheros AR5211-family NIC to
reach any HAL xmit op at runtime; the audit QEMU guest has none β verified:
pciconf -l | grep -i ath β empty). Per the DF-4519/DF-2201 HW-gated protocol
there is no runtime PoC; the defect is source-verified and the fix is
build-validated against the guest kernel:
# guest (root):
cd /usr/src && patch -p1 < /tmp/df4712_fix.diff
make nativekernel KERNCONF=X86_64_GENERIC # rc=0, -Werror (build.log)
Expected: ar5211_xmit.o compiles into the kernel with real runtime q checks;
behavior on this guest is otherwise unchanged (no ath hardware present).
What to look at
VERDICT.mdβ full narrative, reachability analysis, killed candidates.build.logβ full untrimmed nativekernel log (BUILD_RC=0).fix.diffβ runtime q validation for the five exported xmit ops + signed-q rejection inar5211SetTxQueueProps/ar5211GetTxQueueProps.env.txtβ guest uname, AH_ASSERT absence in X86_64_GENERIC, no-ath proof.
DF-4712 VERDICT β ar5211_xmit.c signed-q OOB + inert-assert queue validation
Status: untested (runtime) β source-confirmed defect; runtime reproduction hardware-gated (no Atheros NIC on the guest). Fix build-validated (nativekernel rc=0, -Werror). Same class and same driver guards as sibling DF-4519 (ar5212_xmit, verified 2026-07); this pack covers the ar5211 variant.
The defect
ar5211SetTxQueueProps(struct ath_hal *ah, int q, ...) β
sys/dev/netif/ath/ath_hal/ar5211/ar5211_xmit.c:80-90:
if (q >= HAL_NUM_TX_QUEUES) { /* line 84 β signed int q, no q < 0 check */
...
return AH_FALSE;
}
return ath_hal_setTxQProps(ah, &ahp->ah_txq[q], qInfo); /* line 89 */
qis signed; any negative value passes the>=-only check.ahp->ah_txqisHAL_TX_QUEUE_INFO ah_txq[HAL_NUM_TX_QUEUES=10](ar5211/ar5211.h:121;HAL_NUM_TX_QUEUES=10atah.h:236).ath_hal_setTxQProps(ah.c:951) first readsqi->tqi_type(ah.c:958) and then writes ~15 fields (tqi_ver/qflags/aifs/cwmin/ cwmax/shretry/β¦,ah.c:962-1010) through the out-of-bounds pointer below the array β an OOB kernel read + OOB kernel write into adjacentstruct ath_hal_5211state (and, for large |q|, beyond the object).ar5211GetTxQueueProps(lines 95-106) has the identical signed-q hole β OOB read viaath_hal_getTxQProps.
Additionally, five exported xmit ops gate q only via HALASSERT:
| op | HALASSERT-only line | unchecked sink |
|---|---|---|
ar5211GetTxDP |
:405 | OS_REG_READ(ah, AR_QTXDP(q)) OOB MMIO |
ar5211SetTxDP |
:415 | OS_REG_WRITE(ah, AR_QTXDP(q), txdp) OOB MMIO write |
ar5211StartTxDma |
:435 | OS_REG_WRITE(ah, AR_Q_TXE, 1 << q) UB shift + OOB MMIO |
ar5211NumTxPending |
:458 | AR_QSTS(q) OOB MMIO |
ar5211StopTxDma |
:480 | AR_Q_TXD 1<<q UB + OOB MMIO |
HALASSERT expands to nothing unless the kernel is built with
AH_ASSERT (ah_internal.h:665-676; option only in LINT β verified absent
from the guest's running X86_64_GENERIC config). Production kernels
therefore perform zero validation of q on these paths. (u_int q in these
five means no negative index, but any qβ₯10 reaches register space computed as
AR_QTXDP(q) etc., and 1 << q with qβ₯31 is UB.)
Reachability (why Low/latent)
Every in-tree caller passes driver-internal queue numbers:
if_ath.c:4013-4032βqnum = ath_hal_setuptxqueue(...); the driver rejects-1andqnum >= nitems(sc->sc_txq)before storingaxq_qnum.if_ath.c:4125βath_hal_settxqueueprops(ah, txq->axq_qnum, &qi)uses only those validated qnums.ar5211SetupTxQueueitself only ever returns literal 0/8/9 or -1 (ar5211_xmit.c:119-135).
So there is no unprivileged trigger today; the defect is a latent kernel
OOB-read/write primitive that any future/buggy caller (or a refactored
multiqueq path) can trip. ar5211 has no EEPROM-derived queue-count bound issue
(unlike DF-4520 on ar5212): every op here bounds by the constant
HAL_NUM_TX_QUEUES β the checks are simply signed-only or assert-only.
Verification performed
- Source-traced every caller of the seven exported ops (if_ath.c, if_ath_tx.c, if_ath_beacon.c, if_ath_tdma.c) β all pass validated indexes.
- Confirmed
HALASSERTis inert in production (noAH_ASSERTin X86_64_GENERIC;sys/conf/options:549;ah_internal.h:669-676). - Guest confirmed no Atheros NIC (
pciconf -lβ see env.txt), so no runtime trigger exists on the audit guest. fix.diffapplied to guest/usr/src;make nativekernel KERNCONF=X86_64_GENERICcompleted rc=0 with -Werror (build.log) β the patchedar5211_xmit.ccompiles into the kernel with real runtime bounds checks.
Killed candidates (negative results, this file)
- txRate0
<< AR_XmitRate_Sunmasked (ar5211_xmit.c:537): the 5211 rate tables only emit codes 0x08-0x0f (4-bit field,ar5211_phy.c:31-76; short-preamble mask is 0x04, not 0x10 as on 5212), and every driver caller sources txrate fromrt->info[].rateCode(if_ath_tx.c:1660-1691, 2199) β never out of field. Not reachable. segLenunmasked inar5211FillTxDesc(:589-610): reachable segment lengths are bounded < 0x1000 (802.11 fragmentation threshold ~2346; bpf raw-inject chunks at MCLBYTES), so bits aboveAR_BufLenare never set in practice. Hardening-only (worth masking likepktLen).ar5211GetTxIntrQueuestub leaves*txqsuntouched (:663-667): the driver pre-initializestxqs = 0xffffffff(if_ath.c:2275) β no uninitialized read; conservative "all queues" semantics.ar5211GetTxCompletionRatesstub returns AH_FALSE (:672-676); theath_hal_gettxcompletionratesmacro (if_athvar.h:1420) has no callers in the driver .c files.ar5211ProcTxDesc(:619-657): every decode is a boundedMS()field extraction intostruct ath_tx_status; no array indexing by HW-controlled values. Clean.(type << 26)vsAR_FrmType_S=20(:544 vsar5211desc.h:58-59): quirk inherited verbatim from FreeBSD HAL; functional (frame-type field placement), not memory safety. Not filed.- CAB readytime unsigned arithmetic (:347-350) can wrap for tiny beacon intervals β bad register value, no memory-safety impact.
ar5211UpdateTxTrigLevelISR/non-ISR concurrent lost-update (:38-72): mask-bounded register field, non-security.
Recommended fix
fix.diff (this pack): reject q < 0 in Set/GetTxQueueProps; replace the
inert HALASSERT q-gates in GetTxDP/SetTxDP/StartTxDma/NumTxPending/StopTxDma
with runtime checks returning 0/AH_FALSE β mirrors the accepted DF-4519 fix.
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 to guest /usr/src; make nativekernel KERNCONF=X86_64_GENERIC BUILD_RC=0 with -Werror; patched ar5211_xmit.c compiled into the kernel (build.log:7139). Baseline/patched runtime behavior not observable without an Atheros NIC.
findings/poc/DF-4712/build.log (full untrimmed nativekernel log; decisive lines: 5505 mkdep ar5211_xmit.c, 7139 compile -Werror, final BUILD_RC=0)
Confirmed kernel references
- sys/dev/netif/ath/ath_hal/ar5211/ar5211_xmit.c:84
- sys/dev/netif/ath/ath_hal/ar5211/ar5211_xmit.c:89
- sys/dev/netif/ath/ath_hal/ar5211/ar5211_xmit.c:100
- sys/dev/netif/ath/ath_hal/ar5211/ar5211_xmit.c:405
- sys/dev/netif/ath/ath_hal/ar5211/ar5211_xmit.c:415
- sys/dev/netif/ath/ath_hal/ar5211/ar5211_xmit.c:435
- sys/dev/netif/ath/ath_hal/ar5211/ar5211_xmit.c:458
- sys/dev/netif/ath/ath_hal/ar5211/ar5211_xmit.c:480
- sys/dev/netif/ath/ath_hal/ar5211/ar5211.h:121
- sys/dev/netif/ath/ath_hal/ah_internal.h:665
- sys/dev/netif/ath/ath_hal/ah.c:951
- sys/dev/netif/ath/ath/if_ath.c:4013
Detail
Exploit chain
[]
Evidence (decisive lines)
findings/poc/DF-4712/VERDICT.md (full reachability + killed-candidate narrative); build.log (full nativekernel log, BUILD_RC=0; decisive line 7139 ar5211_xmit.c -Werror); env.txt (no-ath pciconf proof, AH_ASSERT absent from X86_64_GENERIC); fix.diff (7 runtime q checks)
PoC changes
n/a (no runtime PoC attempted; source-only confirmation per DF-4519/DF-2201 hardware-gated protocol)
Verified recommended fix
Replace the inert HALASSERT q-gates in ar5211GetTxDP/SetTxDP/StartTxDma/NumTxPending/StopTxDma with runtime checks (return 0/AH_FALSE on bad q) and reject q<0 in ar5211SetTxQueueProps/ar5211GetTxQueueProps (mirrors accepted DF-4519 fix).
Verdict
untested (runtime): ar5211SetTxQueueProps/ar5211GetTxQueueProps take signed int q and check only q >= HAL_NUM_TX_QUEUES, so q<0 reaches &ahp->ah_txq[q] (ar5211.h:121, HAL_NUM_TX_QUEUES=10) and ath_hal_setTxQProps (ah.c:951) writes ~15 fields through the OOB pointer; GetTxDP/SetTxDP/StartTxDma/NumTxPending/StopTxDma gate q only via HALASSERT, which expands to nothing in production (ah_internal.h:669-676, no AH_ASSERT in X86_64_GENERIC - verified on guest). All in-tree callers pass driver-validated 0..9 (if_ath.c:4013-4032), so no trigger exists on the guest (no Atheros NIC - verified). Source-confirmed defect; ar5211 analogue of sibling DF-4519 (ar5212), which used the same bounds constant bug shape. Fix build-validated: nativekernel KERNCONF=X86_64_GENERIC BUILD_RC=0 with -Werror, patched ar5211_xmit.c compiled into the kernel (build.log:7139).
No comments yet.