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

Commit 509e1b32 authored by Yang Yingliang's avatar Yang Yingliang Committed by Greg Kroah-Hartman
Browse files

net: neigh: don't call kfree_skb() under spin_lock_irqsave()



commit d5485d9dd24e1d04e5509916515260186eb1455c upstream.

It is not allowed to call kfree_skb() from hardware interrupt
context or with interrupts being disabled. So add all skb to
a tmp list, then free them after spin_unlock_irqrestore() at
once.

Fixes: 66ba215cb513 ("neigh: fix possible DoS due to net iface start/stop loop")
Suggested-by: default avatarDenis V. Lunev <den@openvz.org>
Signed-off-by: default avatarYang Yingliang <yangyingliang@huawei.com>
Reviewed-by: default avatarNikolay Aleksandrov <razor@blackwall.org>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent fc91d2db
Loading
Loading
Loading
Loading
+8 −2
Original line number Diff line number Diff line
@@ -226,21 +226,27 @@ static int neigh_del_timer(struct neighbour *n)

static void pneigh_queue_purge(struct sk_buff_head *list, struct net *net)
{
	struct sk_buff_head tmp;
	unsigned long flags;
	struct sk_buff *skb;

	skb_queue_head_init(&tmp);
	spin_lock_irqsave(&list->lock, flags);
	skb = skb_peek(list);
	while (skb != NULL) {
		struct sk_buff *skb_next = skb_peek_next(skb, list);
		if (net == NULL || net_eq(dev_net(skb->dev), net)) {
			__skb_unlink(skb, list);
			dev_put(skb->dev);
			kfree_skb(skb);
			__skb_queue_tail(&tmp, skb);
		}
		skb = skb_next;
	}
	spin_unlock_irqrestore(&list->lock, flags);

	while ((skb = __skb_dequeue(&tmp))) {
		dev_put(skb->dev);
		kfree_skb(skb);
	}
}

static void neigh_flush_dev(struct neigh_table *tbl, struct net_device *dev)