mac80211: use ieee80211_free_txskb to fix possible skb leaks
A few places free skbs using dev_kfree_skb even though they're called after ieee80211_subif_start_xmit might have cloned it for tracking tx status. Use ieee80211_free_txskb here to prevent skb leaks. 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
5bcbc3fcbd
commit
c3e7724b6b
|
@ -34,7 +34,7 @@ void ieee80211_tx_status_irqsafe(struct ieee80211_hw *hw,
|
||||||
skb_queue_len(&local->skb_queue_unreliable);
|
skb_queue_len(&local->skb_queue_unreliable);
|
||||||
while (tmp > IEEE80211_IRQSAFE_QUEUE_LIMIT &&
|
while (tmp > IEEE80211_IRQSAFE_QUEUE_LIMIT &&
|
||||||
(skb = skb_dequeue(&local->skb_queue_unreliable))) {
|
(skb = skb_dequeue(&local->skb_queue_unreliable))) {
|
||||||
dev_kfree_skb_irq(skb);
|
ieee80211_free_txskb(hw, skb);
|
||||||
tmp--;
|
tmp--;
|
||||||
I802_DEBUG_INC(local->tx_status_drop);
|
I802_DEBUG_INC(local->tx_status_drop);
|
||||||
}
|
}
|
||||||
|
@ -159,7 +159,7 @@ static void ieee80211_handle_filtered_frame(struct ieee80211_local *local,
|
||||||
"dropped TX filtered frame, queue_len=%d PS=%d @%lu\n",
|
"dropped TX filtered frame, queue_len=%d PS=%d @%lu\n",
|
||||||
skb_queue_len(&sta->tx_filtered[ac]),
|
skb_queue_len(&sta->tx_filtered[ac]),
|
||||||
!!test_sta_flag(sta, WLAN_STA_PS_STA), jiffies);
|
!!test_sta_flag(sta, WLAN_STA_PS_STA), jiffies);
|
||||||
dev_kfree_skb(skb);
|
ieee80211_free_txskb(&local->hw, skb);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ieee80211_check_pending_bar(struct sta_info *sta, u8 *addr, u8 tid)
|
static void ieee80211_check_pending_bar(struct sta_info *sta, u8 *addr, u8 tid)
|
||||||
|
|
|
@ -354,7 +354,7 @@ static void purge_old_ps_buffers(struct ieee80211_local *local)
|
||||||
total += skb_queue_len(&sta->ps_tx_buf[ac]);
|
total += skb_queue_len(&sta->ps_tx_buf[ac]);
|
||||||
if (skb) {
|
if (skb) {
|
||||||
purged++;
|
purged++;
|
||||||
dev_kfree_skb(skb);
|
ieee80211_free_txskb(&local->hw, skb);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -466,7 +466,7 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx)
|
||||||
ps_dbg(tx->sdata,
|
ps_dbg(tx->sdata,
|
||||||
"STA %pM TX buffer for AC %d full - dropping oldest frame\n",
|
"STA %pM TX buffer for AC %d full - dropping oldest frame\n",
|
||||||
sta->sta.addr, ac);
|
sta->sta.addr, ac);
|
||||||
dev_kfree_skb(old);
|
ieee80211_free_txskb(&local->hw, old);
|
||||||
} else
|
} else
|
||||||
tx->local->total_ps_buffered++;
|
tx->local->total_ps_buffered++;
|
||||||
|
|
||||||
|
@ -1103,7 +1103,7 @@ static bool ieee80211_tx_prep_agg(struct ieee80211_tx_data *tx,
|
||||||
spin_unlock(&tx->sta->lock);
|
spin_unlock(&tx->sta->lock);
|
||||||
|
|
||||||
if (purge_skb)
|
if (purge_skb)
|
||||||
dev_kfree_skb(purge_skb);
|
ieee80211_free_txskb(&tx->local->hw, purge_skb);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* reset session timer */
|
/* reset session timer */
|
||||||
|
@ -1214,7 +1214,7 @@ static bool ieee80211_tx_frags(struct ieee80211_local *local,
|
||||||
#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
|
#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
|
||||||
if (WARN_ON_ONCE(q >= local->hw.queues)) {
|
if (WARN_ON_ONCE(q >= local->hw.queues)) {
|
||||||
__skb_unlink(skb, skbs);
|
__skb_unlink(skb, skbs);
|
||||||
dev_kfree_skb(skb);
|
ieee80211_free_txskb(&local->hw, skb);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -1356,7 +1356,7 @@ static int invoke_tx_handlers(struct ieee80211_tx_data *tx)
|
||||||
if (unlikely(res == TX_DROP)) {
|
if (unlikely(res == TX_DROP)) {
|
||||||
I802_DEBUG_INC(tx->local->tx_handlers_drop);
|
I802_DEBUG_INC(tx->local->tx_handlers_drop);
|
||||||
if (tx->skb)
|
if (tx->skb)
|
||||||
dev_kfree_skb(tx->skb);
|
ieee80211_free_txskb(&tx->local->hw, tx->skb);
|
||||||
else
|
else
|
||||||
__skb_queue_purge(&tx->skbs);
|
__skb_queue_purge(&tx->skbs);
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -1393,7 +1393,7 @@ static bool ieee80211_tx(struct ieee80211_sub_if_data *sdata,
|
||||||
res_prepare = ieee80211_tx_prepare(sdata, &tx, skb);
|
res_prepare = ieee80211_tx_prepare(sdata, &tx, skb);
|
||||||
|
|
||||||
if (unlikely(res_prepare == TX_DROP)) {
|
if (unlikely(res_prepare == TX_DROP)) {
|
||||||
dev_kfree_skb(skb);
|
ieee80211_free_txskb(&local->hw, skb);
|
||||||
goto out;
|
goto out;
|
||||||
} else if (unlikely(res_prepare == TX_QUEUED)) {
|
} else if (unlikely(res_prepare == TX_QUEUED)) {
|
||||||
goto out;
|
goto out;
|
||||||
|
@ -1465,7 +1465,7 @@ void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb)
|
||||||
headroom = max_t(int, 0, headroom);
|
headroom = max_t(int, 0, headroom);
|
||||||
|
|
||||||
if (ieee80211_skb_resize(sdata, skb, headroom, may_encrypt)) {
|
if (ieee80211_skb_resize(sdata, skb, headroom, may_encrypt)) {
|
||||||
dev_kfree_skb(skb);
|
ieee80211_free_txskb(&local->hw, skb);
|
||||||
rcu_read_unlock();
|
rcu_read_unlock();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -2050,8 +2050,10 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
|
||||||
head_need += IEEE80211_ENCRYPT_HEADROOM;
|
head_need += IEEE80211_ENCRYPT_HEADROOM;
|
||||||
head_need += local->tx_headroom;
|
head_need += local->tx_headroom;
|
||||||
head_need = max_t(int, 0, head_need);
|
head_need = max_t(int, 0, head_need);
|
||||||
if (ieee80211_skb_resize(sdata, skb, head_need, true))
|
if (ieee80211_skb_resize(sdata, skb, head_need, true)) {
|
||||||
goto fail;
|
ieee80211_free_txskb(&local->hw, skb);
|
||||||
|
return NETDEV_TX_OK;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (encaps_data) {
|
if (encaps_data) {
|
||||||
|
@ -2184,7 +2186,7 @@ void ieee80211_tx_pending(unsigned long data)
|
||||||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
||||||
|
|
||||||
if (WARN_ON(!info->control.vif)) {
|
if (WARN_ON(!info->control.vif)) {
|
||||||
kfree_skb(skb);
|
ieee80211_free_txskb(&local->hw, skb);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue