]> git.hungrycats.org Git - linux/commitdiff
[NET]: Fix race between neigh-timer_handler and neigh_event_send
authorGreg Banks <gnb@sgi.com>
Tue, 5 Oct 2004 04:37:55 +0000 (21:37 -0700)
committerDavid S. Miller <davem@nuts.davemloft.net>
Tue, 5 Oct 2004 04:37:55 +0000 (21:37 -0700)
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: Greg Banks <gnb@melbourne.sgi.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
net/core/neighbour.c

index d41c265e5a8bb09c66c3110dbf95ac6d48bf82b4..c9bd1b74fc2d5557422a7878bb787cea6d40a9c1 100644 (file)
@@ -810,9 +810,15 @@ static void neigh_timer_handler(unsigned long arg)
                add_timer(&neigh->timer);
        }
        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);
-               neigh->ops->solicit(neigh, skb_peek(&neigh->arp_queue));
+               neigh->ops->solicit(neigh, skb);
                atomic_inc(&neigh->probes);
+               if (skb)
+                       kfree_skb(skb);
        } else {
 out:
                write_unlock(&neigh->lock);