mirror of
https://github.com/outbackdingo/mt76.git
synced 2026-10-24 13:26:48 +00:00
wifi: mt76: mt7996: fix out-of-bounds array access during hardware restart
During hardware restart, link_id can be IEEE80211_LINK_UNSPECIFIED, causing an out-of-bounds array access on msta->link[]. Add mt7996_sta_link() and mt7996_sta_link_protected() helper functions for accessing sta links with proper RCU handling and bounds checking. Use them for any sta link RCU access. Reported-by: Chad Monroe <[email protected]> Signed-off-by: Felix Fietkau <[email protected]>
This commit is contained in:
+2
-2
@@ -645,7 +645,7 @@ mt7996_sta_hw_queue_read(void *data, struct ieee80211_sta *sta)
|
|||||||
if (!mlink)
|
if (!mlink)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
msta_link = rcu_dereference(msta->link[link_id]);
|
msta_link = mt7996_sta_link(msta, link_id);
|
||||||
if (!msta_link)
|
if (!msta_link)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@@ -1018,7 +1018,7 @@ static ssize_t mt7996_link_sta_fixed_rate_set(struct file *file,
|
|||||||
|
|
||||||
mutex_lock(&dev->mt76.mutex);
|
mutex_lock(&dev->mt76.mutex);
|
||||||
|
|
||||||
msta_link = mt76_dereference(msta->link[link_sta->link_id], &dev->mt76);
|
msta_link = mt7996_sta_link_protected(dev, msta, link_sta->link_id);
|
||||||
if (!msta_link) {
|
if (!msta_link) {
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
goto out;
|
goto out;
|
||||||
|
|||||||
+3
-3
@@ -48,7 +48,7 @@ static struct mt76_wcid *mt7996_rx_get_wcid(struct mt7996_dev *dev,
|
|||||||
if (mlink->band_idx != band_idx)
|
if (mlink->band_idx != band_idx)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
msta_link = rcu_dereference(msta->link[i]);
|
msta_link = mt7996_sta_link(msta, i);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1038,7 +1038,7 @@ int mt7996_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
|
|||||||
if (link_id != wcid->link_id && link_id != IEEE80211_LINK_UNSPECIFIED) {
|
if (link_id != wcid->link_id && link_id != IEEE80211_LINK_UNSPECIFIED) {
|
||||||
if (msta) {
|
if (msta) {
|
||||||
struct mt7996_sta_link *msta_link =
|
struct mt7996_sta_link *msta_link =
|
||||||
rcu_dereference(msta->link[link_id]);
|
mt7996_sta_link(msta, link_id);
|
||||||
|
|
||||||
if (msta_link)
|
if (msta_link)
|
||||||
wcid = &msta_link->wcid;
|
wcid = &msta_link->wcid;
|
||||||
@@ -1344,7 +1344,7 @@ mt7996_mac_tx_free(struct mt7996_dev *dev, void *data, int len)
|
|||||||
IEEE80211_MLD_MAX_NUM_LINKS) {
|
IEEE80211_MLD_MAX_NUM_LINKS) {
|
||||||
struct mt7996_sta_link *msta_link;
|
struct mt7996_sta_link *msta_link;
|
||||||
|
|
||||||
msta_link = rcu_dereference(msta->link[id]);
|
msta_link = mt7996_sta_link(msta, id);
|
||||||
if (!msta_link)
|
if (!msta_link)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
|||||||
+8
-9
@@ -207,8 +207,7 @@ mt7996_set_hw_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
|
|||||||
struct mt7996_sta *msta;
|
struct mt7996_sta *msta;
|
||||||
|
|
||||||
msta = (struct mt7996_sta *)sta->drv_priv;
|
msta = (struct mt7996_sta *)sta->drv_priv;
|
||||||
msta_link = mt76_dereference(msta->link[link_id],
|
msta_link = mt7996_sta_link_protected(dev, msta, link_id);
|
||||||
&dev->mt76);
|
|
||||||
if (!msta_link)
|
if (!msta_link)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
@@ -1268,7 +1267,7 @@ mt7996_mac_sta_event(struct mt7996_dev *dev, struct ieee80211_vif *vif,
|
|||||||
if (!link)
|
if (!link)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
msta_link = mt76_dereference(msta->link[link_id], &dev->mt76);
|
msta_link = mt7996_sta_link_protected(dev, msta, link_id);
|
||||||
if (!msta_link)
|
if (!msta_link)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@@ -1458,7 +1457,7 @@ static void mt7996_tx(struct ieee80211_hw *hw,
|
|||||||
if (msta) {
|
if (msta) {
|
||||||
struct mt7996_sta_link *msta_link;
|
struct mt7996_sta_link *msta_link;
|
||||||
|
|
||||||
msta_link = rcu_dereference(msta->link[link_id]);
|
msta_link = mt7996_sta_link(msta, link_id);
|
||||||
if (msta_link)
|
if (msta_link)
|
||||||
wcid = &msta_link->wcid;
|
wcid = &msta_link->wcid;
|
||||||
}
|
}
|
||||||
@@ -1824,7 +1823,7 @@ static void mt7996_link_sta_rc_update(struct ieee80211_hw *hw,
|
|||||||
|
|
||||||
rcu_read_lock();
|
rcu_read_lock();
|
||||||
|
|
||||||
msta_link = rcu_dereference(msta->link[link_sta->link_id]);
|
msta_link = mt7996_sta_link(msta, link_sta->link_id);
|
||||||
if (msta_link) {
|
if (msta_link) {
|
||||||
struct mt7996_dev *dev = mt7996_hw_dev(hw);
|
struct mt7996_dev *dev = mt7996_hw_dev(hw);
|
||||||
|
|
||||||
@@ -1841,7 +1840,7 @@ static void mt7996_sta_rate_ctrl_update(void *data, struct ieee80211_sta *sta)
|
|||||||
struct mt7996_sta_link *msta_link;
|
struct mt7996_sta_link *msta_link;
|
||||||
u32 *changed = data;
|
u32 *changed = data;
|
||||||
|
|
||||||
msta_link = rcu_dereference(msta->link[msta->deflink_id]);
|
msta_link = mt7996_sta_link(msta, msta->deflink_id);
|
||||||
if (msta_link)
|
if (msta_link)
|
||||||
mt7996_link_rate_ctrl_update(&changed, msta_link);
|
mt7996_link_rate_ctrl_update(&changed, msta_link);
|
||||||
}
|
}
|
||||||
@@ -1891,7 +1890,7 @@ static void mt7996_sta_set_4addr(struct ieee80211_hw *hw,
|
|||||||
if (!link)
|
if (!link)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
msta_link = mt76_dereference(msta->link[link_id], &dev->mt76);
|
msta_link = mt7996_sta_link_protected(dev, msta, link_id);
|
||||||
if (!msta_link)
|
if (!msta_link)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@@ -1929,7 +1928,7 @@ static void mt7996_sta_set_decap_offload(struct ieee80211_hw *hw,
|
|||||||
if (!link)
|
if (!link)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
msta_link = mt76_dereference(msta->link[link_id], &dev->mt76);
|
msta_link = mt7996_sta_link_protected(dev, msta, link_id);
|
||||||
if (!msta_link)
|
if (!msta_link)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@@ -2269,7 +2268,7 @@ mt7996_net_fill_forward_path(struct ieee80211_hw *hw,
|
|||||||
if (!link)
|
if (!link)
|
||||||
return -EIO;
|
return -EIO;
|
||||||
|
|
||||||
msta_link = rcu_dereference(msta->link[msta->deflink_id]);
|
msta_link = mt7996_sta_link(msta, msta->deflink_id);
|
||||||
if (!msta_link)
|
if (!msta_link)
|
||||||
return -EIO;
|
return -EIO;
|
||||||
|
|
||||||
|
|||||||
+11
-11
@@ -1126,7 +1126,7 @@ mt7996_mcu_bss_basic_tlv(struct sk_buff *skb,
|
|||||||
struct mt7996_sta_link *msta_link;
|
struct mt7996_sta_link *msta_link;
|
||||||
int link_id = link_conf->link_id;
|
int link_id = link_conf->link_id;
|
||||||
|
|
||||||
msta_link = rcu_dereference(msta->link[link_id]);
|
msta_link = mt7996_sta_link(msta, link_id);
|
||||||
if (msta_link)
|
if (msta_link)
|
||||||
sta_wlan_idx = msta_link->wcid.idx;
|
sta_wlan_idx = msta_link->wcid.idx;
|
||||||
}
|
}
|
||||||
@@ -1364,7 +1364,7 @@ int mt7996_mcu_add_tx_ba(struct mt7996_dev *dev,
|
|||||||
struct mt7996_sta_link *msta_link;
|
struct mt7996_sta_link *msta_link;
|
||||||
struct mt7996_vif_link *link;
|
struct mt7996_vif_link *link;
|
||||||
|
|
||||||
msta_link = mt76_dereference(msta->link[link_id], &dev->mt76);
|
msta_link = mt7996_sta_link_protected(dev, msta, link_id);
|
||||||
if (!msta_link)
|
if (!msta_link)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@@ -1398,7 +1398,7 @@ int mt7996_mcu_add_rx_ba(struct mt7996_dev *dev,
|
|||||||
struct mt7996_sta_link *msta_link;
|
struct mt7996_sta_link *msta_link;
|
||||||
struct mt7996_vif_link *link;
|
struct mt7996_vif_link *link;
|
||||||
|
|
||||||
msta_link = mt76_dereference(msta->link[link_id], &dev->mt76);
|
msta_link = mt7996_sta_link_protected(dev, msta, link_id);
|
||||||
if (!msta_link)
|
if (!msta_link)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@@ -2127,7 +2127,7 @@ int mt7996_mcu_set_fixed_field(struct mt7996_dev *dev, struct mt7996_sta *msta,
|
|||||||
if (!mlink)
|
if (!mlink)
|
||||||
goto error_unlock;
|
goto error_unlock;
|
||||||
|
|
||||||
msta_link = rcu_dereference(msta->link[link_id]);
|
msta_link = mt7996_sta_link(msta, link_id);
|
||||||
if (!msta_link)
|
if (!msta_link)
|
||||||
goto error_unlock;
|
goto error_unlock;
|
||||||
|
|
||||||
@@ -2216,7 +2216,7 @@ mt7996_mcu_add_rate_ctrl_fixed(struct mt7996_dev *dev, struct mt7996_sta *msta,
|
|||||||
if (!link)
|
if (!link)
|
||||||
goto error_unlock;
|
goto error_unlock;
|
||||||
|
|
||||||
msta_link = rcu_dereference(msta->link[link_id]);
|
msta_link = mt7996_sta_link(msta, link_id);
|
||||||
if (!msta_link)
|
if (!msta_link)
|
||||||
goto error_unlock;
|
goto error_unlock;
|
||||||
|
|
||||||
@@ -2423,7 +2423,7 @@ int mt7996_mcu_add_rate_ctrl(struct mt7996_dev *dev, struct mt7996_sta *msta,
|
|||||||
if (!link)
|
if (!link)
|
||||||
goto error_unlock;
|
goto error_unlock;
|
||||||
|
|
||||||
msta_link = rcu_dereference(msta->link[link_id]);
|
msta_link = mt7996_sta_link(msta, link_id);
|
||||||
if (!msta_link)
|
if (!msta_link)
|
||||||
goto error_unlock;
|
goto error_unlock;
|
||||||
|
|
||||||
@@ -2512,7 +2512,7 @@ mt7996_mcu_sta_mld_setup_tlv(struct mt7996_dev *dev, struct sk_buff *skb,
|
|||||||
unsigned int link_id;
|
unsigned int link_id;
|
||||||
struct tlv *tlv;
|
struct tlv *tlv;
|
||||||
|
|
||||||
msta_link = mt76_dereference(msta->link[msta->deflink_id], &dev->mt76);
|
msta_link = mt7996_sta_link_protected(dev, msta, msta->deflink_id);
|
||||||
if (!msta_link)
|
if (!msta_link)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -2526,8 +2526,8 @@ mt7996_mcu_sta_mld_setup_tlv(struct mt7996_dev *dev, struct sk_buff *skb,
|
|||||||
mld_setup->primary_id = cpu_to_le16(msta_link->wcid.idx);
|
mld_setup->primary_id = cpu_to_le16(msta_link->wcid.idx);
|
||||||
|
|
||||||
if (nlinks > 1) {
|
if (nlinks > 1) {
|
||||||
msta_link = mt76_dereference(msta->link[msta->seclink_id],
|
msta_link = mt7996_sta_link_protected(dev, msta,
|
||||||
&dev->mt76);
|
msta->seclink_id);
|
||||||
if (!msta_link)
|
if (!msta_link)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -2538,7 +2538,7 @@ mt7996_mcu_sta_mld_setup_tlv(struct mt7996_dev *dev, struct sk_buff *skb,
|
|||||||
for_each_sta_active_link(vif, sta, link_sta, link_id) {
|
for_each_sta_active_link(vif, sta, link_sta, link_id) {
|
||||||
struct mt7996_vif_link *link;
|
struct mt7996_vif_link *link;
|
||||||
|
|
||||||
msta_link = mt76_dereference(msta->link[link_id], &dev->mt76);
|
msta_link = mt7996_sta_link_protected(dev, msta, link_id);
|
||||||
if (!msta_link)
|
if (!msta_link)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@@ -2682,7 +2682,7 @@ void mt7996_mcu_update_sta_rec_bw(void *data, struct ieee80211_sta *sta)
|
|||||||
if (!link_sta)
|
if (!link_sta)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
msta_link = mt76_dereference(msta->link[link_id], &dev->mt76);
|
msta_link = mt7996_sta_link_protected(dev, msta, link_id);
|
||||||
if (!msta_link)
|
if (!msta_link)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|||||||
@@ -624,6 +624,25 @@ mt7996_vif_conf_link(struct mt7996_dev *dev, struct ieee80211_vif *vif,
|
|||||||
link_conf);
|
link_conf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline struct mt7996_sta_link *
|
||||||
|
mt7996_sta_link(struct mt7996_sta *msta, u8 link_id)
|
||||||
|
{
|
||||||
|
if (link_id >= IEEE80211_MLD_MAX_NUM_LINKS)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return rcu_dereference(msta->link[link_id]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline struct mt7996_sta_link *
|
||||||
|
mt7996_sta_link_protected(struct mt7996_dev *dev, struct mt7996_sta *msta,
|
||||||
|
u8 link_id)
|
||||||
|
{
|
||||||
|
if (link_id >= IEEE80211_MLD_MAX_NUM_LINKS)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return mt76_dereference(msta->link[link_id], &dev->mt76);
|
||||||
|
}
|
||||||
|
|
||||||
#define mt7996_for_each_phy(dev, phy) \
|
#define mt7996_for_each_phy(dev, phy) \
|
||||||
for (int __i = 0; __i < ARRAY_SIZE((dev)->radio_phy); __i++) \
|
for (int __i = 0; __i < ARRAY_SIZE((dev)->radio_phy); __i++) \
|
||||||
if (((phy) = (dev)->radio_phy[__i]) != NULL)
|
if (((phy) = (dev)->radio_phy[__i]) != NULL)
|
||||||
|
|||||||
Reference in New Issue
Block a user