mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2025-01-17 18:56:24 +00:00
wifi: mac80211: use two-phase skb reclamation in ieee80211_do_stop()
[ Upstream commit 9d301de12da6e1bb069a9835c38359b8e8135121 ] Since '__dev_queue_xmit()' should be called with interrupts enabled, the following backtrace: ieee80211_do_stop() ... spin_lock_irqsave(&local->queue_stop_reason_lock, flags) ... ieee80211_free_txskb() ieee80211_report_used_skb() ieee80211_report_ack_skb() cfg80211_mgmt_tx_status_ext() nl80211_frame_tx_status() genlmsg_multicast_netns() genlmsg_multicast_netns_filtered() nlmsg_multicast_filtered() netlink_broadcast_filtered() do_one_broadcast() netlink_broadcast_deliver() __netlink_sendskb() netlink_deliver_tap() __netlink_deliver_tap_skb() dev_queue_xmit() __dev_queue_xmit() ; with IRQS disabled ... spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags) issues the warning (as reported by syzbot reproducer): WARNING: CPU: 2 PID: 5128 at kernel/softirq.c:362 __local_bh_enable_ip+0xc3/0x120 Fix this by implementing a two-phase skb reclamation in 'ieee80211_do_stop()', where actual work is performed outside of a section with interrupts disabled. Fixes: 5061b0c2b906 ("mac80211: cooperate more with network namespaces") Reported-by: syzbot+1a3986bbd3169c307819@syzkaller.appspotmail.com Closes: https://syzkaller.appspot.com/bug?extid=1a3986bbd3169c307819 Signed-off-by: Dmitry Antipov <dmantipov@yandex.ru> Link: https://patch.msgid.link/20240906123151.351647-1-dmantipov@yandex.ru Signed-off-by: Johannes Berg <johannes.berg@intel.com> Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
parent
87032ebecc
commit
db5ca4b42c
@ -466,6 +466,7 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, bool going_do
|
||||
{
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
unsigned long flags;
|
||||
struct sk_buff_head freeq;
|
||||
struct sk_buff *skb, *tmp;
|
||||
u32 hw_reconf_flags = 0;
|
||||
int i, flushed;
|
||||
@ -658,18 +659,32 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, bool going_do
|
||||
skb_queue_purge(&sdata->status_queue);
|
||||
}
|
||||
|
||||
/*
|
||||
* Since ieee80211_free_txskb() may issue __dev_queue_xmit()
|
||||
* which should be called with interrupts enabled, reclamation
|
||||
* is done in two phases:
|
||||
*/
|
||||
__skb_queue_head_init(&freeq);
|
||||
|
||||
/* unlink from local queues... */
|
||||
spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
|
||||
for (i = 0; i < IEEE80211_MAX_QUEUES; i++) {
|
||||
skb_queue_walk_safe(&local->pending[i], skb, tmp) {
|
||||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
||||
if (info->control.vif == &sdata->vif) {
|
||||
__skb_unlink(skb, &local->pending[i]);
|
||||
ieee80211_free_txskb(&local->hw, skb);
|
||||
__skb_queue_tail(&freeq, skb);
|
||||
}
|
||||
}
|
||||
}
|
||||
spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
|
||||
|
||||
/* ... and perform actual reclamation with interrupts enabled. */
|
||||
skb_queue_walk_safe(&freeq, skb, tmp) {
|
||||
__skb_unlink(skb, &freeq);
|
||||
ieee80211_free_txskb(&local->hw, skb);
|
||||
}
|
||||
|
||||
if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
|
||||
ieee80211_txq_remove_vlan(local, sdata);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user