Commit bb2f7bea authored by Greg Banks's avatar Greg Banks Committed by David S. Miller

[NET]: Fix race between neigh-timer_handler and neigh_event_send

Fix a race between neigh_timer_handler() calling down to arp_solicit()
with an sk_buff peeked from the head of the neigh->arp_queue, and
neigh_event_send() unqueuing and freeing the head of the same queue
because it's reached the maximum length of 3, by taking an extra
sk_buff reference while holding neigh->lock.
Signed-off-by: default avatarGreg Banks <gnb@melbourne.sgi.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 42f1b541
...@@ -810,9 +810,15 @@ static void neigh_timer_handler(unsigned long arg) ...@@ -810,9 +810,15 @@ static void neigh_timer_handler(unsigned long arg)
add_timer(&neigh->timer); add_timer(&neigh->timer);
} }
if (neigh->nud_state & (NUD_INCOMPLETE | NUD_PROBE)) { if (neigh->nud_state & (NUD_INCOMPLETE | NUD_PROBE)) {
struct sk_buff *skb = skb_peek(&neigh->arp_queue);
/* keep skb alive even if arp_queue overflows */
if (skb)
skb_get(skb);
write_unlock(&neigh->lock); write_unlock(&neigh->lock);
neigh->ops->solicit(neigh, skb_peek(&neigh->arp_queue)); neigh->ops->solicit(neigh, skb);
atomic_inc(&neigh->probes); atomic_inc(&neigh->probes);
if (skb)
kfree_skb(skb);
} else { } else {
out: out:
write_unlock(&neigh->lock); write_unlock(&neigh->lock);
......
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