Commit 2bb9966c authored by Felix Fietkau's avatar Felix Fietkau Committed by Ben Hutchings

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

commit 81357a28 upstream.

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>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
Signed-off-by: default avatarBen Hutchings <ben@decadent.org.uk>
parent c293fd77
...@@ -64,7 +64,8 @@ static void ath_tx_update_baw(struct ath_softc *sc, struct ath_atx_tid *tid, ...@@ -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, static struct ath_buf *ath_tx_setup_buffer(struct ath_softc *sc,
struct ath_txq *txq, struct ath_txq *txq,
struct ath_atx_tid *tid, struct ath_atx_tid *tid,
struct sk_buff *skb); struct sk_buff *skb,
bool dequeue);
enum { enum {
MCS_HT20, MCS_HT20,
...@@ -761,7 +762,7 @@ static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc, ...@@ -761,7 +762,7 @@ static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc,
fi = get_frame_info(skb); fi = get_frame_info(skb);
bf = fi->bf; bf = fi->bf;
if (!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) if (!bf)
continue; continue;
...@@ -1669,7 +1670,7 @@ static void ath_tx_send_ampdu(struct ath_softc *sc, struct ath_atx_tid *tid, ...@@ -1669,7 +1670,7 @@ static void ath_tx_send_ampdu(struct ath_softc *sc, struct ath_atx_tid *tid,
return; return;
} }
bf = ath_tx_setup_buffer(sc, txctl->txq, tid, skb); bf = ath_tx_setup_buffer(sc, txctl->txq, tid, skb, false);
if (!bf) if (!bf)
return; return;
...@@ -1696,7 +1697,7 @@ static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq, ...@@ -1696,7 +1697,7 @@ static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq,
bf = fi->bf; bf = fi->bf;
if (!bf) if (!bf)
bf = ath_tx_setup_buffer(sc, txq, tid, skb); bf = ath_tx_setup_buffer(sc, txq, tid, skb, false);
if (!bf) if (!bf)
return; return;
...@@ -1761,7 +1762,8 @@ u8 ath_txchainmask_reduction(struct ath_softc *sc, u8 chainmask, u32 rate) ...@@ -1761,7 +1762,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, static struct ath_buf *ath_tx_setup_buffer(struct ath_softc *sc,
struct ath_txq *txq, struct ath_txq *txq,
struct ath_atx_tid *tid, 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_common *common = ath9k_hw_common(sc->sc_ah);
struct ath_frame_info *fi = get_frame_info(skb); struct ath_frame_info *fi = get_frame_info(skb);
...@@ -1802,6 +1804,8 @@ static struct ath_buf *ath_tx_setup_buffer(struct ath_softc *sc, ...@@ -1802,6 +1804,8 @@ static struct ath_buf *ath_tx_setup_buffer(struct ath_softc *sc,
return bf; return bf;
error: error:
if (dequeue)
__skb_unlink(skb, &tid->buf_q);
dev_kfree_skb_any(skb); dev_kfree_skb_any(skb);
return NULL; return NULL;
} }
...@@ -1833,7 +1837,7 @@ static void ath_tx_start_dma(struct ath_softc *sc, struct sk_buff *skb, ...@@ -1833,7 +1837,7 @@ static void ath_tx_start_dma(struct ath_softc *sc, struct sk_buff *skb,
*/ */
ath_tx_send_ampdu(sc, tid, skb, txctl); ath_tx_send_ampdu(sc, tid, skb, txctl);
} else { } else {
bf = ath_tx_setup_buffer(sc, txctl->txq, tid, skb); bf = ath_tx_setup_buffer(sc, txctl->txq, tid, skb, false);
if (!bf) if (!bf)
goto out; goto out;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment