: Fix race between pneigh deletion and ipv6's ndisc_recv_ns.
Subsystems (3)
PATCH 1/1 : Fix race between pneigh deletion and ipv6's ndisc_recv_ns.
Proxy neighbors do not have any reference counting, so any caller of pneigh_lookup (unless it's a netlink triggered add/del routine) should _not_ perform any actions on the found proxy entry.
There's one exception from this rule - the ipv6's ndisc_recv_ns() uses found entry to check the flags for NTF_ROUTER.
This creates a race between the ndisc and pneigh_delete - after the pneigh is returned to the caller, the nd_tbl.lock is dropped and the deleting procedure may proceed.
One of the fixes would be to add a reference counting, but this problem exists for ndisc only. Besides such a patch would be too big for -rc4.
So I propose to introduce a __pneigh_lookup() which is supposed to be called with the lock held and use it in ndisc code to check the flags on alive pneigh entry.
If this is OK, is there a real need in proxy neighbors reference counting for 2.6.26 :) ?
---
include/net/neighbour.h +2 -0
@@ -218,6 +218,8 @@ extern unsigned long neigh_rand_reach_time(unsigned long base);extern void pneigh_enqueue (struct neigh_table *tbl,struct neigh_parms *p,struct sk_buff *skb);extern struct pneigh_entry *pneigh_lookup (struct neigh_table *tbl,struct net *net,const void *key,struct net_device *dev,int creat); +extern struct pneigh_entry *__pneigh_lookup (struct neigh_table *tbl, +struct net *net,const void *key,struct net_device *dev);extern int pneigh_delete (struct neigh_table *tbl,struct net *net,const void *key,struct net_device *dev);extern void neigh_app_ns (struct neighbour *n);
net/core/neighbour.c +22 -0
@@ -466,6 +466,28 @@ out_neigh_release: goto out; } +struct pneigh_entry *__pneigh_lookup (struct neigh_table *tbl, +struct net *net,const void *pkey,struct net_device *dev) +{ +struct pneigh_entry *n; +int key_len = tbl->key_len; +u32 hash_val = *(u32 *)(pkey + key_len -4 ); + + hash_val ^= (hash_val >>16 ); + hash_val ^= hash_val >>8 ; + hash_val ^= hash_val >>4 ; + hash_val &=PNEIGH_HASHMASK ; + +for (n = tbl->phash_buckets[hash_val]; n; n = n->next) { +if (!memcmp (n->key, pkey, key_len) && + (n->net == net) && + (n->dev == dev || !n->dev)) +break ; + } + +return n; +} +struct pneigh_entry *pneigh_lookup (struct neigh_table *tbl,struct net *net,const void *pkey,struct net_device *dev,int creat)
net/ipv6/ndisc.c +17 -3
@@ -676,6 +676,20 @@ static void ndisc_solicit(struct neighbour *neigh, struct sk_buff *skb) } } +static struct pneigh_entry *neigh_check_router (struct net_device *dev, +struct in6_addr *addr,int *is_router) +{ +struct pneigh_entry *n; + +read_lock_bh (&nd_tbl.lock); + n =__pneigh_lookup (&nd_tbl, &init_net, addr, dev); +if (n !=NULL ) + *is_router = (n->flags &NTF_ROUTER ); +read_unlock_bh (&nd_tbl.lock); + +return n; +} +static void ndisc_recv_ns (struct sk_buff *skb) {struct nd_msg *msg = (struct nd_msg *)skb_transport_header (skb);
@@ -790,8 +804,8 @@ static void ndisc_recv_ns(struct sk_buff *skb)if (ipv6_chk_acast_addr (dev, &msg->target) || (idev->cnf.forwarding && (ipv6_devconf.proxy_ndp || idev->cnf.proxy_ndp) && - (pneigh =pneigh_lookup (&nd_tbl, &init_net, - &msg->target, dev,0 )) !=NULL )) { + (pneigh =neigh_check_router (dev, &msg->target, + &is_router)) !=NULL )) { if (!(NEIGH_CB(skb)->flags & LOCALLY_ENQUEUED) && skb->pkt_type != PACKET_HOST && inc != 0 &&
@@ -812,7 +826,7 @@ static void ndisc_recv_ns(struct sk_buff *skb) goto out; } - is_router = !!(pneigh ? pneigh->flags &NTF_ROUTER : idev->cnf.forwarding); + is_router = !!(pneigh ? is_router : idev->cnf.forwarding);if (dad) {struct in6_addr maddr;
Hi, David.
You picked up the patch with /proc/net symlink, but skipped this one, while it was sent earlier. Is it _that_ bad :) ?
Thanks,
Pavel
Quoted 118 lines
Proxy neighbors do not have any reference counting, so any caller of
pneigh_lookup(unless it's a netlink triggered add/del routine) should _not_ perform any actions on the found proxy entry.There's one exception from this rule - the ipv6's
ndisc_recv_ns()uses found entry to check the flags forNTF_ROUTER.This creates a race between the ndisc and
pneigh_delete- after the pneigh is returned to the caller, the nd_tbl.lock is dropped and the deleting procedure may proceed.One of the fixes would be to add a reference counting, but this problem exists for ndisc only. Besides such a patch would be too big for -rc4.
So I propose to introduce a
__pneigh_lookup()which is supposed to be called with the lock held and use it in ndisc code to check the flags on alive pneigh entry.If this is OK, is there a real need in proxy neighbors reference counting for 2.6.26 :) ?
Signed-off-by Pavel Emelyanov <[email protected]>---
include/net/neighbour.h +2
-0@@ -218,6 +218,8 @@ extern unsigned long neigh_rand_reach_time(unsigned long base);extern void pneigh_enqueue (struct neigh_table *tbl,struct neigh_parms *p,struct sk_buff *skb);extern struct pneigh_entry *pneigh_lookup (struct neigh_table *tbl,struct net *net,const void *key,struct net_device *dev,int creat); +extern struct pneigh_entry *__pneigh_lookup (struct neigh_table *tbl, +struct net *net,const void *key,struct net_device *dev);extern int pneigh_delete (struct neigh_table *tbl,struct net *net,const void *key,struct net_device *dev);extern void neigh_app_ns (struct neighbour *n);net/core/neighbour.c +22
-0@@ -466,6 +466,28 @@ out_neigh_release: goto out; } +struct pneigh_entry *__pneigh_lookup (struct neigh_table *tbl, +struct net *net,const void *pkey,struct net_device *dev) +{ +struct pneigh_entry *n; +int key_len = tbl->key_len; +u32 hash_val = *(u32 *)(pkey + key_len -4 ); + + hash_val ^= (hash_val >>16 ); + hash_val ^= hash_val >>8 ; + hash_val ^= hash_val >>4 ; + hash_val &=PNEIGH_HASHMASK ; + +for (n = tbl->phash_buckets[hash_val]; n; n = n->next) { +if (!memcmp (n->key, pkey, key_len) && + (n->net == net) && + (n->dev == dev || !n->dev)) +break ; + } + +return n; +} +struct pneigh_entry *pneigh_lookup (struct neigh_table *tbl,struct net *net,const void *pkey,struct net_device *dev,int creat)net/ipv6/ndisc.c +17
-3@@ -676,6 +676,20 @@ static void ndisc_solicit(struct neighbour *neigh, struct sk_buff *skb) } } +static struct pneigh_entry *neigh_check_router (struct net_device *dev, +struct in6_addr *addr,int *is_router) +{ +struct pneigh_entry *n; + +read_lock_bh (&nd_tbl.lock); + n =__pneigh_lookup (&nd_tbl, &init_net, addr, dev); +if (n !=NULL ) + *is_router = (n->flags &NTF_ROUTER ); +read_unlock_bh (&nd_tbl.lock); + +return n; +} +static void ndisc_recv_ns (struct sk_buff *skb) {struct nd_msg *msg = (struct nd_msg *)skb_transport_header (skb);@@ -790,8 +804,8 @@ static void ndisc_recv_ns(struct sk_buff *skb)if (ipv6_chk_acast_addr (dev, &msg->target) || (idev->cnf.forwarding && (ipv6_devconf.proxy_ndp || idev->cnf.proxy_ndp) && - (pneigh =pneigh_lookup (&nd_tbl, &init_net, - &msg->target, dev,0 )) !=NULL )) { + (pneigh =neigh_check_router (dev, &msg->target, + &is_router)) !=NULL )) { if (!(NEIGH_CB(skb)->flags & LOCALLY_ENQUEUED) && skb->pkt_type != PACKET_HOST && inc != 0 &&@@ -812,7 +826,7 @@ static void ndisc_recv_ns(struct sk_buff *skb) goto out; } - is_router = !!(pneigh ? pneigh->flags &NTF_ROUTER : idev->cnf.forwarding); + is_router = !!(pneigh ? is_router : idev->cnf.forwarding);if (dad) {struct in6_addr maddr;
David Miller
maintainerFrom: Pavel Emelyanov <[email protected]>
Date: Tue, 11 Mar 2008 16:24:39 +0300
Quoted 2 lines
You picked up the patch with
/proc/netsymlink, but skipped this one, while it was sent earlier. Is it _that_ bad :) ?
I am travelling and giving presentations in Japan, and this patch is in my backlog to look at :-)
PATCH 1/1 : Fix race between pneigh deletion and ipv6's ndisc_recv_ns - V2
Quoted 8 lines · David Miller
From: Pavel Emelyanov <[email protected]>
Date: Tue, 11 Mar 2008 16:24:39 +0300Quoted 2 lines
You picked up the patch with
/proc/netsymlink, but skipped this one, while it was sent earlier. Is it _that_ bad :) ?I am travelling and giving presentations in Japan, and this patch is in my backlog to look at :-)
The patch does not apply anymore due to the ndisc modification to be per namespace. I modified it to take the namespace into account and initialized the is_router variable to avoid a compilation warning.
Subject: [PATCH][NEIGH]: Fix race between pneigh deletion and ipv6's ndisc_recv_ns - V2
From: Pavel Emelyanov <[email protected]>
Proxy neighbors do not have any reference counting, so any caller of pneigh_lookup (unless it's a netlink triggered add/del routine) should _not_ perform any actions on the found proxy entry.
There's one exception from this rule - the ipv6's ndisc_recv_ns() uses found entry to check the flags for NTF_ROUTER.
This creates a race between the ndisc and pneigh_delete - after the pneigh is returned to the caller, the nd_tbl.lock is dropped and the deleting procedure may proceed.
One of the fixes would be to add a reference counting, but this problem exists for ndisc only. Besides such a patch would be too big for -rc4.
So I propose to introduce a __pneigh_lookup() which is supposed to be called with the lock held and use it in ndisc code to check the flags on alive pneigh entry.
If this is OK, is there a real need in proxy neighbors reference counting for 2.6.26 :) ?
--- include/net/neighbour.h | 2 ++ net/core/neighbour.c | 22 ++++++++++++++++++++++ net/ipv6/ndisc.c | 23 +++++++++++++++++++---- 3 files changed, 43 insertions(+), 4 deletions(-)
include/net/neighbour.h +2 -0
@@ -218,6 +218,8 @@ extern unsigned long neigh_rand_reach_textern void pneigh_enqueue (struct neigh_table *tbl,struct neigh_parms *p,struct sk_buff *skb);extern struct pneigh_entry *pneigh_lookup (struct neigh_table *tbl,struct net *net,const void *key,struct net_device *dev,int creat); +extern struct pneigh_entry *__pneigh_lookup (struct neigh_table *tbl, +struct net *net,const void *key,struct net_device *dev);extern int pneigh_delete (struct neigh_table *tbl,struct net *net,const void *key,struct net_device *dev);extern void neigh_app_ns (struct neighbour *n);
net/core/neighbour.c +22 -0
@@ -466,6 +466,28 @@ out_neigh_release: goto out; } +struct pneigh_entry *__pneigh_lookup (struct neigh_table *tbl, +struct net *net,const void *pkey,struct net_device *dev) +{ +struct pneigh_entry *n; +int key_len = tbl->key_len; +u32 hash_val = *(u32 *)(pkey + key_len -4 ); + + hash_val ^= (hash_val >>16 ); + hash_val ^= hash_val >>8 ; + hash_val ^= hash_val >>4 ; + hash_val &=PNEIGH_HASHMASK ; + +for (n = tbl->phash_buckets[hash_val]; n; n = n->next) { +if (!memcmp (n->key, pkey, key_len) && + (n->net == net) && + (n->dev == dev || !n->dev)) +break ; + } + +return n; +} +struct pneigh_entry *pneigh_lookup (struct neigh_table *tbl,struct net *net,const void *pkey,struct net_device *dev,int creat)
net/ipv6/ndisc.c +19 -4
@@ -659,6 +659,21 @@ static void ndisc_solicit(struct neighbo } } +static struct pneigh_entry *neigh_check_router (struct net_device *dev, +struct in6_addr *addr, +int *is_router) +{ +struct pneigh_entry *n; + +read_lock_bh (&nd_tbl.lock); + n =__pneigh_lookup (&nd_tbl, dev->nd_net, addr, dev); +if (n !=NULL ) + *is_router = (n->flags &NTF_ROUTER ); +read_unlock_bh (&nd_tbl.lock); + +return n; +} +static void ndisc_recv_ns (struct sk_buff *skb) {struct nd_msg *msg = (struct nd_msg *)skb_transport_header (skb);
@@ -675,7 +690,7 @@ static void ndisc_recv_ns(struct sk_buffstruct pneigh_entry *pneigh =NULL ;int dad =ipv6_addr_any (saddr);int inc; -int is_router; +int is_router =0 ;if (ipv6_addr_is_multicast (&msg->target)) { ND_PRINTK2(KERN_WARNING
@@ -774,8 +789,8 @@ static void ndisc_recv_ns(struct sk_buffif (ipv6_chk_acast_addr (dev, &msg->target) || (idev->cnf.forwarding && (ipv6_devconf.proxy_ndp || idev->cnf.proxy_ndp) && - (pneigh =pneigh_lookup (&nd_tbl, dev->nd_net, - &msg->target, dev,0 )) !=NULL )) { + (pneigh =neigh_check_router (dev, &msg->target, + &is_router)) !=NULL )) { if (!(NEIGH_CB(skb)->flags & LOCALLY_ENQUEUED) && skb->pkt_type != PACKET_HOST && inc != 0 &&
@@ -796,7 +811,7 @@ static void ndisc_recv_ns(struct sk_buff goto out; } - is_router = !!(pneigh ? pneigh->flags &NTF_ROUTER : idev->cnf.forwarding); + is_router = !!(pneigh ? is_router : idev->cnf.forwarding);if (dad) {struct in6_addr maddr;
Re: [PATCH][NEIGH]: Fix race between pneigh deletion and ipv6's ndisc_recv_ns - V2
In article <[email protected]> (at Wed, 12 Mar 2008 10:41:01 +0100), Daniel Lezcano <[email protected]> says:
Quoted 6 lines
Subject: [PATCH][NEIGH]: Fix race between pneigh deletion and ipv6's
ndisc_recv_ns- V2
From: Pavel Emelyanov <[email protected]>Proxy neighbors do not have any reference counting, so any caller of
pneigh_lookup(unless it's a netlink triggered add/del routine) should _not_ perform any actions on the found proxy entry.
Good catch and I'm basically okay with this but, please rename neigh_check_router to pndisc_check_router().
Thanks.
--yoshfuji
Re: [PATCH][NEIGH]: Fix race between pneigh deletion and ipv6's ndisc_recv_ns - V2
In reply to Daniel LezcanoQuoted 4 lines · Daniel Lezcano
Quoted 3 lines · David Miller
From: Pavel Emelyanov <[email protected]>
Date: Tue, 11 Mar 2008 16:24:39 +0300
Quoted 9 lines
Quoted 4 lines
Quoted 2 lines
You picked up the patch with
/proc/netsymlink, but skipped this one, while it was sent earlier. Is it _that_ bad :) ?I am travelling and giving presentations in Japan, and this patch is in my backlog to look at :-)
The patch does not apply anymore due to the ndisc modification to be per namespace. I modified it to take the namespace into account and initialized the
is_routervariable to avoid a compilation warning.
My patch applies to net-2.6, while yours does not. Which tree is it for?
Re: [PATCH][NEIGH]: Fix race between pneigh deletion and ipv6's ndisc_recv_ns - V2
Quoted 5 lines · Pavel Emelyanov
Quoted 4 lines · Daniel Lezcano
Quoted 3 lines · David Miller
From: Pavel Emelyanov <[email protected]>
Date: Tue, 11 Mar 2008 16:24:39 +0300
Quoted 8 lines
Quoted 6 lines
Quoted 4 lines
Quoted 2 lines
You picked up the patch with
/proc/netsymlink, but skipped this one, while it was sent earlier. Is it _that_ bad :) ?I am travelling and giving presentations in Japan, and this patch is in my backlog to look at :-)
The patch does not apply anymore due to the ndisc modification to be per namespace. I modified it to take the namespace into account and initialized the
is_routervariable to avoid a compilation warning.My patch applies to net-2.6, while yours does not. Which tree is it for?
well, hum, net-2.6.26 :|
Re: [PATCH][NEIGH]: Fix race between pneigh deletion and ipv6's ndisc_recv_ns - V2
Quoted 10 lines · Daniel Lezcano
Quoted 9 lines · Pavel Emelyanov
Quoted 8 lines · Daniel Lezcano
Quoted 7 lines · David Miller
From: Pavel Emelyanov <[email protected]>
Date: Tue, 11 Mar 2008 16:24:39 +0300Quoted 2 lines
You picked up the patch with
/proc/netsymlink, but skipped this one, while it was sent earlier. Is it _that_ bad :) ?I am travelling and giving presentations in Japan, and this patch is in my backlog to look at :-)
Quoted 8 lines
Quoted 6 lines
Quoted 4 lines
The patch does not apply anymore due to the ndisc modification to be per namespace. I modified it to take the namespace into account and initialized the
is_routervariable to avoid a compilation warning.My patch applies to net-2.6, while yours does not. Which tree is it for?
well, hum, net-2.6.26 :|
OK.
Then I will fix the comments from YOSHIFUJI and re-send the patch for net-2.6.
Thanks,
Pavel
Re: [PATCH][NEIGH]: Fix race between pneigh deletion and ipv6's ndisc_recv_ns - V2
Quoted 9 lines · Pavel Emelyanov
Quoted 8 lines · Daniel Lezcano
Quoted 7 lines · Pavel Emelyanov
Quoted 6 lines · Daniel Lezcano
Quoted 5 lines · David Miller
From: Pavel Emelyanov <[email protected]>
Date: Tue, 11 Mar 2008 16:24:39 +0300Quoted 2 lines
You picked up the patch with
/proc/netsymlink, but skipped this one, while it was sent earlier. Is it _that_ bad :) ?
Quoted 8 lines
Quoted 6 lines
Quoted 5 lines
Quoted 4 lines
Quoted 2 lines
I am travelling and giving presentations in Japan, and this patch is in my backlog to look at :-)
The patch does not apply anymore due to the ndisc modification to be per namespace. I modified it to take the namespace into account and initialized the
is_routervariable to avoid a compilation warning.My patch applies to net-2.6, while yours does not. Which tree is it for?
well, hum, net-2.6.26 :|
OK. Then I will fix the comments from YOSHIFUJI and re-send the patch for net-2.6.
Ok, sorry for the confusion.
David Miller
maintainerFrom: Pavel Emelyanov <[email protected]>
Date: Thu, 06 Mar 2008 14:18:05 +0300
net/core/neighbour.c out_neigh_release: · line 471
Quoted 3 lines
net/core/neighbour.c +3
-0+struct pneigh_entry *__pneigh_lookup (struct neigh_table *tbl, +struct net *net,const void *pkey,struct net_device *dev) +{
You don't export this to modules, so when IPV6 is modular the build fails.
Please fix this up and resubmit, thanks.