diff options
author | jdp <jdp@FreeBSD.org> | 1999-12-09 17:09:37 +0000 |
---|---|---|
committer | jdp <jdp@FreeBSD.org> | 1999-12-09 17:09:37 +0000 |
commit | 6a226314fd38d358e306ed7216f5d1336267e8af (patch) | |
tree | bc31fe5b62472ab7ed64ad2b3ecc98323d59b49b /sys/net/route.c | |
parent | 542194f894f6e82e2e832b2911180ca6dec9dbbd (diff) | |
download | FreeBSD-src-6a226314fd38d358e306ed7216f5d1336267e8af.zip FreeBSD-src-6a226314fd38d358e306ed7216f5d1336267e8af.tar.gz |
Fix a route table leak in rtalloc() and rtalloc_ign(). It is
possible for ro->ro_rt to be non-NULL even though the RTF_UP flag
is cleared. (Example: a routing daemon or the "route" command
deletes a cloned route in active use by a TCP connection.) In that
case, the code was clobbering a reference to the routing table
entry without decrementing the entry's reference count.
The splnet() call probably isn't needed, but I haven't been able
to prove that yet. It isn't significant from a performance standpoint
since it is executed very rarely.
Reviewed by: wollman and others in the freebsd-current mailing list
Diffstat (limited to 'sys/net/route.c')
-rw-r--r-- | sys/net/route.c | 17 |
1 files changed, 12 insertions, 5 deletions
diff --git a/sys/net/route.c b/sys/net/route.c index 04608f5..45e0e39 100644 --- a/sys/net/route.c +++ b/sys/net/route.c @@ -88,9 +88,7 @@ void rtalloc(ro) register struct route *ro; { - if (ro->ro_rt && ro->ro_rt->rt_ifp && (ro->ro_rt->rt_flags & RTF_UP)) - return; /* XXX */ - ro->ro_rt = rtalloc1(&ro->ro_dst, 1, 0UL); + rtalloc_ign(ro, 0UL); } void @@ -98,8 +96,17 @@ rtalloc_ign(ro, ignore) register struct route *ro; u_long ignore; { - if (ro->ro_rt && ro->ro_rt->rt_ifp && (ro->ro_rt->rt_flags & RTF_UP)) - return; /* XXX */ + struct rtentry *rt; + int s; + + if ((rt = ro->ro_rt) != NULL) { + if (rt->rt_ifp != NULL && rt->rt_flags & RTF_UP) + return; + /* XXX - We are probably always at splnet here already. */ + s = splnet(); + RTFREE(rt); + splx(s); + } ro->ro_rt = rtalloc1(&ro->ro_dst, 1, ignore); } |