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: Felix Fietkau <nbd@openwrt.org> Cc: stable@vger.kernel.org Signed-off-by: John W. Linville <linville@tuxdriver.com>
This commit is contained in:
parent
ceea2a5196
commit
81357a281d
1 changed files with 10 additions and 6 deletions
|
@ -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;
|
||||
|
||||
|
|
Loading…
Reference in a new issue