aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorHerbert Xu <herbert@gondor.apana.org.au>2006-02-02 19:55:45 -0500
committerDavid S. Miller <davem@davemloft.net>2006-02-02 19:55:45 -0500
commit4641e7a334adf6856300a98e7296dfc886c446af (patch)
tree39030c280f6fbfa183c2ce5a0db37118ce5a7810 /net
parent42c5e15f18d63c1ecf79d52bdaf4ea31cd22416d (diff)
[IPV6]: Don't hold extra ref count in ipv6_ifa_notify
Currently the logic in ipv6_ifa_notify is to hold an extra reference count for addrconf dst's that get added to the routing table. Thus, when addrconf dst entries are taken out of the routing table, we need to drop that dst. However, addrconf dst entries may be removed from the routing table by means other than __ipv6_ifa_notify. So we're faced with the choice of either fixing up all places where addrconf dst entries are removed, or dropping the extra reference count altogether. I chose the latter because the ifp itself always holds a dst reference count of 1 while it's alive. This is dropped just before we kfree the ifp object. Therefore we know that in __ipv6_ifa_notify we will always hold that count. This bug was found by Eric W. Biederman. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r--net/ipv6/addrconf.c6
1 files changed, 1 insertions, 5 deletions
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index d328d5986143..1db50487916b 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -3321,9 +3321,7 @@ static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp)
3321 3321
3322 switch (event) { 3322 switch (event) {
3323 case RTM_NEWADDR: 3323 case RTM_NEWADDR:
3324 dst_hold(&ifp->rt->u.dst); 3324 ip6_ins_rt(ifp->rt, NULL, NULL, NULL);
3325 if (ip6_ins_rt(ifp->rt, NULL, NULL, NULL))
3326 dst_release(&ifp->rt->u.dst);
3327 if (ifp->idev->cnf.forwarding) 3325 if (ifp->idev->cnf.forwarding)
3328 addrconf_join_anycast(ifp); 3326 addrconf_join_anycast(ifp);
3329 break; 3327 break;
@@ -3334,8 +3332,6 @@ static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp)
3334 dst_hold(&ifp->rt->u.dst); 3332 dst_hold(&ifp->rt->u.dst);
3335 if (ip6_del_rt(ifp->rt, NULL, NULL, NULL)) 3333 if (ip6_del_rt(ifp->rt, NULL, NULL, NULL))
3336 dst_free(&ifp->rt->u.dst); 3334 dst_free(&ifp->rt->u.dst);
3337 else
3338 dst_release(&ifp->rt->u.dst);
3339 break; 3335 break;
3340 } 3336 }
3341} 3337}