β¬’ DragonFlyBSD Kernel Audit
← triage Β· dashboard
DF-5267

Five linear rate lookups store MTW_RIDX_MAX (36) on a miss; the stale ridx then indexes rt2860_rates[36] one element out of bounds (mtw_tx/mtw_set_tx_desc/tx_mgt/radiotap wt_rate)

Summary

rt2860_rates[36] but loops exit with ridx==36 on a miss (media_change/iter_func/newassoc/sendprot/tx_param) feeding rt2860_rates[ridx] one-past-end reads in tx/set_tx_desc/tx_mgt + radiotap wt_rate (bpf-visible). Requires an off-table rate (odd net80211 state) - speculative. Twin of DF-0984. Clamp-after-miss fix at all 5 sites.

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-5267 Β· 3 files
FileTypeDescriptionSize
env.txt β€” 183 B view raw
fix.diff β€” 1.3 KB view raw
verdict.json β€” 2.9 KB view raw

Fix verification

not_testable
baseline no→ patch + rebuild →patched clean

fix.diff authored and verified with 'git apply --check' against the pristine sys/ tree, but cannot be kernel-tested: the guest has no USB controller and no MT7601U device model, so neither baseline nor patched kernel behavior is exercisable. Hardware-gated: not_testable.

fix.diff (git-apply clean); VERDICT.md
↓ fix.diffper-fix-DF-5267

Confirmed kernel references

Detail

Exploit chain

node with ni_txrate not in rt2860_rates -> amrr_ridx=36 -> data->ridx=36 -> rt2860_rates[36] OOB read -> value lands in TXWI MCS field and radiotap wt_rate (bpf listeners)

Evidence (decisive lines)

Code-cited: 5 loops + 4 use sites; array size counted (36 entries). untested (hardware-gated)

Verified recommended fix

Clamp ridx to MTW_RIDX_CCK1 after each miss

Verdict

rt2860_rates[] (if_mtwreg.h:963-998) has exactly 36 entries (indices 0..35) and MTW_RIDX_MAX=36. Five lookup loops exit with ridx==MTW_RIDX_MAX when the searched rate is not in the table - mtw_media_change (1720-1723, rn->fix_ridx), mtw_iter_func (2320-2327, rn->amrr_ridx, e.g. an ni_txrate not among the 36 codes), mtw_newassoc (2394-2396, mn->mgt_ridx), mtw_sendprot (3349-3351) and mtw_tx_param (3428-3430) (data->ridx). The stored ridx is later used to index rt2860_rates[ridx] one element past the end: mtw_tx (3115-3122, ctl_ridx), mtw_set_tx_desc (2998-3034, .mcs/.phy), mtw_tx_mgt (3258, .rate) and the tx callback's radiotap tap->wt_rate = rt2860_rates[data->ridx].rate (2846) which leaks the adjacent static bytes to any radiotap listener. One-element OOB read of a const array (adjacent rodata), impact is a 1-2 byte info leak of static data plus wrong hardware fields; a miss requires an off-table rate (e.g. odd ni_txrate), hence speculative. Twin of DF-0984 (urtwn ridx2rate).