Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 81357a28 authored by Felix Fietkau's avatar Felix Fietkau Committed by John W. Linville
Browse files

ath9k: fix a use-after-free-bug when ath_tx_setup_buffer() fails



ath_tx_setup_buffer() can fail if there is no ath_buf left, or if mapping DMA
failed. In this case it frees the skb passed to it.
If ath_tx_setup_buffer is called from ath_tx_form_aggr, the skb is still
linked into the tid buffer list and must be dequeued before being released.

Signed-off-by: default avatarFelix Fietkau <nbd@openwrt.org>
Cc: stable@vger.kernel.org
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent ceea2a51
Loading
Loading
Loading
Loading
+10 −6
Original line number Diff line number Diff line
@@ -64,7 +64,8 @@ static void ath_tx_update_baw(struct ath_softc *sc, struct ath_atx_tid *tid,
static struct ath_buf *ath_tx_setup_buffer(struct ath_softc *sc,
					   struct ath_txq *txq,
					   struct ath_atx_tid *tid,
					   struct sk_buff *skb);
					   struct sk_buff *skb,
					   bool dequeue);

enum {
	MCS_HT20,
@@ -811,7 +812,7 @@ static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc,
		fi = get_frame_info(skb);
		bf = fi->bf;
		if (!fi->bf)
			bf = ath_tx_setup_buffer(sc, txq, tid, skb);
			bf = ath_tx_setup_buffer(sc, txq, tid, skb, true);

		if (!bf)
			continue;
@@ -1726,7 +1727,7 @@ static void ath_tx_send_ampdu(struct ath_softc *sc, struct ath_atx_tid *tid,
		return;
	}

	bf = ath_tx_setup_buffer(sc, txctl->txq, tid, skb);
	bf = ath_tx_setup_buffer(sc, txctl->txq, tid, skb, false);
	if (!bf)
		return;

@@ -1753,7 +1754,7 @@ static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq,

	bf = fi->bf;
	if (!bf)
		bf = ath_tx_setup_buffer(sc, txq, tid, skb);
		bf = ath_tx_setup_buffer(sc, txq, tid, skb, false);

	if (!bf)
		return;
@@ -1814,7 +1815,8 @@ u8 ath_txchainmask_reduction(struct ath_softc *sc, u8 chainmask, u32 rate)
static struct ath_buf *ath_tx_setup_buffer(struct ath_softc *sc,
					   struct ath_txq *txq,
					   struct ath_atx_tid *tid,
					   struct sk_buff *skb)
					   struct sk_buff *skb,
					   bool dequeue)
{
	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
	struct ath_frame_info *fi = get_frame_info(skb);
@@ -1863,6 +1865,8 @@ static struct ath_buf *ath_tx_setup_buffer(struct ath_softc *sc,
	return bf;

error:
	if (dequeue)
		__skb_unlink(skb, &tid->buf_q);
	dev_kfree_skb_any(skb);
	return NULL;
}
@@ -1893,7 +1897,7 @@ static void ath_tx_start_dma(struct ath_softc *sc, struct sk_buff *skb,
		 */
		ath_tx_send_ampdu(sc, tid, skb, txctl);
	} else {
		bf = ath_tx_setup_buffer(sc, txctl->txq, tid, skb);
		bf = ath_tx_setup_buffer(sc, txctl->txq, tid, skb, false);
		if (!bf)
			return;