[PATCH] wifi: mac80211: use frame link_id when adjusting link_sta on reorder release

From: Noah Weinberger

Date: Sun Nov 08 2026 - 16:55:36 EST


Hello,

In ieee80211_rx_handlers(), when frames are released from the BA reorder
buffer on timeout, rx->link_sta is re-fetched using the *previous*
rx->link_id instead of the frame's own status->link_id. For a legacy
(non-MLO) client on an MLO access point,
ieee80211_release_reorder_timeout() passes link_id = -1 and
ieee80211_rx_data_set_sta() never updates rx->link_id, so the adjust
block evaluates rcu_dereference(rx->sta->link[-1]).

link[-1] aliases deflink.pub, the last member of the struct embedded
directly before link[] in struct sta_info, which is always non-NULL - so
the existing NULL fallback cannot fire and rx->link_sta becomes a
struct ieee80211_link_sta * that the RX handlers then treat as a
struct link_sta_info *.

ieee80211_rx_h_sta_process() subsequently writes statistics through that
type-confused pointer (a fragments counter, a u64 byte counter fed with
the attacker-controlled frame length, signal EWMAs and chain-signal
values) at fixed offsets inside struct ieee80211_sta around deflink. The
corruption is intra-object and therefore invisible to KASAN; depending
on the exact layout it can reach the link[] pointer array, nmi,
nan_sched and the driver-private area that follow deflink. At minimum
this is a remotely triggered crash on MLO APs serving legacy clients;
worse outcomes are layout-dependent.

The one-word fix below uses the frame's own status->link_id, which also
restores the intended behaviour for MLD peers interleaving frames from
two links inside one reorder window (the current code fetches the link
STA of the *previous* frame's link).

Affected version/commit: mainline fa4ad798f6f681031775266044ba1b0cf3c670bd (v7.4-rc1, 2026-11-07), net/mac80211/rx.c:4243-4255 (adjust block), rx.c:4375-4404 (ieee80211_rx_data_set_sta), rx.c:4410-4426 (ieee80211_release_reorder_timeout).
Introduced in the v7.4 merge window (regression vs v7.3).

This was found during an assisted (AI-supported) static source review of
mainline fa4ad798f6f681031775266044ba1b0cf3c670bd (v7.4-rc1, 2026-11-07); every code path cited below was re-verified by the
reporter against that tree. The patch below has NOT been compiled and has
NOT been runtime tested, and no reproducer was produced - the triggering
conditions are described above instead. Please treat this as a report for
verification rather than a battle-tested fix.

Fixes: [fill in before sending - on a full clone run:
git log -S 'rcu_dereference(rx->sta->link[rx->link_id])' --oneline -- net/mac80211/rx.c]
Reported-by: [your name and email]
---
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index ecee934..836d571 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -4244,7 +4244,7 @@ static void ieee80211_rx_handlers(struct ieee80211_rx_data *rx,
unlikely(rx->link_id != status->link_id)) {
if (rx->sta) {
rx->link_sta =
- rcu_dereference(rx->sta->link[rx->link_id]);
+ rcu_dereference(rx->sta->link[status->link_id]);

/* Link got disabled, just use deflink */
if (!rx->link_sta)