Commit b5cd1fd6 authored by Felix Fietkau's avatar Felix Fietkau
Browse files

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: default avatarFelix Fietkau <nbd@nbd.name>
parent cd3f3873
Loading
Loading
Loading
Loading
+23 −22
Original line number Diff line number Diff line
@@ -1497,30 +1497,39 @@ static void mt7615_mac_add_txs(struct mt7615_dev *dev, void *data)
}

static void
mt7615_mac_tx_free_token(struct mt7615_dev *dev, u16 token)
mt7615_txwi_free(struct mt7615_dev *dev, struct mt76_txwi_cache *txwi)
{
	struct mt76_dev *mdev = &dev->mt76;
	struct mt76_txwi_cache *txwi;
	__le32 *txwi_data;
	u32 val;
	u8 wcid;

	trace_mac_tx_free(dev, token);
	txwi = mt76_token_put(mdev, token);
	if (!txwi)
		return;
	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);

	mt7615_txp_skb_unmap(mdev, txwi);
	if (txwi->skb) {
	mt76_tx_complete_skb(mdev, wcid, txwi->skb);

out:
	txwi->skb = NULL;
	mt76_put_txwi(mdev, txwi);
}

	mt76_put_txwi(mdev, txwi);
static void
mt7615_mac_tx_free_token(struct mt7615_dev *dev, u16 token)
{
	struct mt76_dev *mdev = &dev->mt76;
	struct mt76_txwi_cache *txwi;

	trace_mac_tx_free(dev, token);
	txwi = mt76_token_put(mdev, token);
	if (!txwi)
		return;

	mt7615_txwi_free(dev, txwi);
}

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;

	spin_lock_bh(&dev->mt76.token_lock);
	idr_for_each_entry(&dev->mt76.token, txwi, id) {
		mt7615_txp_skb_unmap(&dev->mt76, 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);
	}
	idr_for_each_entry(&dev->mt76.token, txwi, id)
		mt7615_txwi_free(dev, txwi);
	spin_unlock_bh(&dev->mt76.token_lock);
	idr_destroy(&dev->mt76.token);
}