mt76: mt7615: fix skb use-after-free on mac reset
When clearing all existing pending tx slots, mt76_tx_complete_skb needs to be used to free the skbs, to ensure that they are cleared from the status list as well. Cc: stable@vger.kernel.org Signed-off-by: Felix Fietkau <nbd@nbd.name>
This commit is contained in:
@@ -1496,31 +1496,40 @@ out:
|
|||||||
rcu_read_unlock();
|
rcu_read_unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
mt7615_txwi_free(struct mt7615_dev *dev, struct mt76_txwi_cache *txwi)
|
||||||
|
{
|
||||||
|
struct mt76_dev *mdev = &dev->mt76;
|
||||||
|
__le32 *txwi_data;
|
||||||
|
u32 val;
|
||||||
|
u8 wcid;
|
||||||
|
|
||||||
|
mt7615_txp_skb_unmap(mdev, txwi);
|
||||||
|
if (!txwi->skb)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
txwi_data = (__le32 *)mt76_get_txwi_ptr(mdev, txwi);
|
||||||
|
val = le32_to_cpu(txwi_data[1]);
|
||||||
|
wcid = FIELD_GET(MT_TXD1_WLAN_IDX, val);
|
||||||
|
mt76_tx_complete_skb(mdev, wcid, txwi->skb);
|
||||||
|
|
||||||
|
out:
|
||||||
|
txwi->skb = NULL;
|
||||||
|
mt76_put_txwi(mdev, txwi);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
mt7615_mac_tx_free_token(struct mt7615_dev *dev, u16 token)
|
mt7615_mac_tx_free_token(struct mt7615_dev *dev, u16 token)
|
||||||
{
|
{
|
||||||
struct mt76_dev *mdev = &dev->mt76;
|
struct mt76_dev *mdev = &dev->mt76;
|
||||||
struct mt76_txwi_cache *txwi;
|
struct mt76_txwi_cache *txwi;
|
||||||
__le32 *txwi_data;
|
|
||||||
u32 val;
|
|
||||||
u8 wcid;
|
|
||||||
|
|
||||||
trace_mac_tx_free(dev, token);
|
trace_mac_tx_free(dev, token);
|
||||||
txwi = mt76_token_put(mdev, token);
|
txwi = mt76_token_put(mdev, token);
|
||||||
if (!txwi)
|
if (!txwi)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
txwi_data = (__le32 *)mt76_get_txwi_ptr(mdev, txwi);
|
mt7615_txwi_free(dev, txwi);
|
||||||
val = le32_to_cpu(txwi_data[1]);
|
|
||||||
wcid = FIELD_GET(MT_TXD1_WLAN_IDX, val);
|
|
||||||
|
|
||||||
mt7615_txp_skb_unmap(mdev, txwi);
|
|
||||||
if (txwi->skb) {
|
|
||||||
mt76_tx_complete_skb(mdev, wcid, txwi->skb);
|
|
||||||
txwi->skb = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
mt76_put_txwi(mdev, txwi);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mt7615_mac_tx_free(struct mt7615_dev *dev, struct sk_buff *skb)
|
static void mt7615_mac_tx_free(struct mt7615_dev *dev, struct sk_buff *skb)
|
||||||
@@ -2029,16 +2038,8 @@ void mt7615_tx_token_put(struct mt7615_dev *dev)
|
|||||||
int id;
|
int id;
|
||||||
|
|
||||||
spin_lock_bh(&dev->mt76.token_lock);
|
spin_lock_bh(&dev->mt76.token_lock);
|
||||||
idr_for_each_entry(&dev->mt76.token, txwi, id) {
|
idr_for_each_entry(&dev->mt76.token, txwi, id)
|
||||||
mt7615_txp_skb_unmap(&dev->mt76, txwi);
|
mt7615_txwi_free(dev, txwi);
|
||||||
if (txwi->skb) {
|
|
||||||
struct ieee80211_hw *hw;
|
|
||||||
|
|
||||||
hw = mt76_tx_status_get_hw(&dev->mt76, txwi->skb);
|
|
||||||
ieee80211_free_txskb(hw, txwi->skb);
|
|
||||||
}
|
|
||||||
mt76_put_txwi(&dev->mt76, txwi);
|
|
||||||
}
|
|
||||||
spin_unlock_bh(&dev->mt76.token_lock);
|
spin_unlock_bh(&dev->mt76.token_lock);
|
||||||
idr_destroy(&dev->mt76.token);
|
idr_destroy(&dev->mt76.token);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user