[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20260102200315.290015-4-zbowling@gmail.com>
Date: Fri, 2 Jan 2026 12:03:12 -0800
From: Zac Bowling <zbowling@...il.com>
To: zbowling@...il.com
Cc: deren.wu@...iatek.com,
kvalo@...nel.org,
linux-kernel@...r.kernel.org,
linux-mediatek@...ts.infradead.org,
linux-wireless@...r.kernel.org,
lorenzo@...nel.org,
nbd@....name,
ryder.lee@...iatek.com,
sean.wang@...iatek.com
Subject: [PATCH] wifi: mt76: mt7925: add NULL checks for MLO link pointers in MCU functions
Several MCU functions dereference pointers returned by mt792x_sta_to_link()
and mt792x_vif_to_link() without checking for NULL. During MLO state
transitions, these functions can return NULL when link state is being
set up or torn down, causing kernel NULL pointer dereferences.
Add NULL checks in the following functions:
- mt7925_mcu_sta_hdr_trans_tlv(): Check mlink before dereferencing wcid
- mt7925_mcu_wtbl_update_hdr_trans(): Check mlink and mconf before use
- mt7925_mcu_sta_amsdu_tlv(): Check mlink before setting amsdu flag
- mt7925_mcu_sta_mld_tlv(): Check mconf and mlink in link iteration loop
- mt7925_mcu_sta_update(): Initialize mlink to NULL and check both
link_sta and mlink in the ternary condition
These race conditions can occur during:
- MLO link setup/teardown
- Station add/remove operations
- Firmware command generation during state transitions
The fixes follow the pattern used in mt7996 and ath12k drivers for
similar MLO link state handling.
Signed-off-by: Zac Bowling <zac@...bowling.com>
---
mt7925/mcu.c | 14 ++++++++++++--
1 file changed, 12 insertions(+), 2 deletions(-)
diff --git a/mt7925/mcu.c b/mt7925/mcu.c
index bd38807e..b9c4b99d 100644
--- a/mt7925/mcu.c
+++ b/mt7925/mcu.c
@@ -1087,6 +1087,8 @@ mt7925_mcu_sta_hdr_trans_tlv(struct sk_buff *skb,
struct mt792x_link_sta *mlink;
mlink = mt792x_sta_to_link(msta, link_sta->link_id);
+ if (!mlink)
+ return;
wcid = &mlink->wcid;
} else {
wcid = &mvif->sta.deflink.wcid;
@@ -1120,6 +1122,9 @@ int mt7925_mcu_wtbl_update_hdr_trans(struct mt792x_dev *dev,
link_sta = mt792x_sta_to_link_sta(vif, sta, link_id);
mconf = mt792x_vif_to_link(mvif, link_id);
+ if (!mlink || !mconf)
+ return -EINVAL;
+
skb = __mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mconf->mt76,
&mlink->wcid,
MT7925_STA_UPDATE_MAX_SIZE);
@@ -1741,6 +1746,8 @@ mt7925_mcu_sta_amsdu_tlv(struct sk_buff *skb,
amsdu->amsdu_en = true;
mlink = mt792x_sta_to_link(msta, link_sta->link_id);
+ if (!mlink)
+ return;
mlink->wcid.amsdu = true;
switch (link_sta->agg.max_amsdu_len) {
@@ -1935,6 +1942,9 @@ mt7925_mcu_sta_mld_tlv(struct sk_buff *skb,
mconf = mt792x_vif_to_link(mvif, i);
mlink = mt792x_sta_to_link(msta, i);
+ if (!mconf || !mlink)
+ continue;
+
mld->link[cnt].wlan_id = cpu_to_le16(mlink->wcid.idx);
mld->link[cnt++].bss_idx = mconf->mt76.idx;
@@ -2027,13 +2037,13 @@ int mt7925_mcu_sta_update(struct mt792x_dev *dev,
.rcpi = to_rcpi(rssi),
};
struct mt792x_sta *msta;
- struct mt792x_link_sta *mlink;
+ struct mt792x_link_sta *mlink = NULL;
if (link_sta) {
msta = (struct mt792x_sta *)link_sta->sta->drv_priv;
mlink = mt792x_sta_to_link(msta, link_sta->link_id);
}
- info.wcid = link_sta ? &mlink->wcid : &mvif->sta.deflink.wcid;
+ info.wcid = (link_sta && mlink) ? &mlink->wcid : &mvif->sta.deflink.wcid;
info.newly = state != MT76_STA_INFO_STATE_ASSOC;
return mt7925_mcu_sta_cmd(&dev->mphy, &info);
--
2.51.0
Powered by blists - more mailing lists