From: | Peter Avalos <pavalos@xxxxxxxxxxxx> |
Date: | Sun, 16 Sep 2007 22:32:24 -0400 |
Mail-followup-to: | bugs@crater.dragonflybsd.org |
On Sat, Sep 01, 2007 at 05:54:10PM -0400, Peter Avalos wrote: > On Wed, Aug 29, 2007 at 09:50:27PM -0700, Matthew Dillon wrote: > > > > So we need to audit all the code that manipulates the in_ifaddrhead > > list and check for structures that might get freed without being removed > > from the list. > > > > I'm having no luck. Got any pointers/ideas? > Looking around FreeBSD source I saw this, and was wondering if it could help? http://www.theshell.com/cgi-bin/gitweb.cgi?p=freebsd-src.git;a=commitdiff;h=16f96b132d344c7682df05b3bf74278150a5b3b1 commit 16f96b132d344c7682df05b3bf74278150a5b3b1 Author: peadar <peadar> Date: Wed May 25 13:52:03 2005 +0000 Separate out address-detaching part of if_detach into if_purgeaddrs, so if_tap doesn't need to rely on locally-rolled code to do same. The observable symptom of if_tap's bzero'ing the address details was a crash in "ifconfig tap0" after an if_tap device was closed. Reported By: Matti Saarinen (mjsaarin at cc dot helsinki dot fi) diff --git a/sys/net/if.c b/sys/net/if.c index 8aff428..f056329 100644 --- a/sys/net/if.c +++ b/sys/net/if.c @@ -27,7 +27,7 @@ * SUCH DAMAGE. * * @(#)if.c 8.5 (Berkeley) 1/9/95 - * $FreeBSD: src/sys/net/if.c,v 1.227 2005/04/20 09:30:54 glebius Exp $ + * $FreeBSD: src/sys/net/if.c,v 1.228 2005/05/25 13:52:03 peadar Exp $ */ #include "opt_compat.h" @@ -530,13 +530,52 @@ if_attachdomain1(struct ifnet *ifp) } /* + * Remove any network addresses from an interface. + */ + +void +if_purgeaddrs(struct ifnet *ifp) +{ + struct ifaddr *ifa, *next; + + TAILQ_FOREACH_SAFE(ifa, &ifp->if_addrhead, ifa_link, next) { + + if (ifa->ifa_addr->sa_family == AF_LINK) + continue; +#ifdef INET + /* XXX: Ugly!! ad hoc just for INET */ + if (ifa->ifa_addr && ifa->ifa_addr->sa_family == AF_INET) { + struct ifaliasreq ifr; + + bzero(&ifr, sizeof(ifr)); + ifr.ifra_addr = *ifa->ifa_addr; + if (ifa->ifa_dstaddr) + ifr.ifra_broadaddr = *ifa->ifa_dstaddr; + if (in_control(NULL, SIOCDIFADDR, (caddr_t)&ifr, ifp, + NULL) == 0) + continue; + } +#endif /* INET */ +#ifdef INET6 + if (ifa->ifa_addr && ifa->ifa_addr->sa_family == AF_INET6) { + in6_purgeaddr(ifa); + /* ifp_addrhead is already updated */ + continue; + } +#endif /* INET6 */ + TAILQ_REMOVE(&ifp->if_addrhead, ifa, ifa_link); + IFAFREE(ifa); + } +} + +/* * Detach an interface, removing it from the * list of "active" interfaces. */ void if_detach(struct ifnet *ifp) { - struct ifaddr *ifa, *next; + struct ifaddr *ifa; struct radix_node_head *rnh; int s; int i; @@ -568,35 +607,7 @@ if_detach(struct ifnet *ifp) altq_detach(&ifp->if_snd); #endif - for (ifa = TAILQ_FIRST(&ifp->if_addrhead); ifa; ifa = next) { - next = TAILQ_NEXT(ifa, ifa_link); - - if (ifa->ifa_addr->sa_family == AF_LINK) - continue; -#ifdef INET - /* XXX: Ugly!! ad hoc just for INET */ - if (ifa->ifa_addr && ifa->ifa_addr->sa_family == AF_INET) { - struct ifaliasreq ifr; - - bzero(&ifr, sizeof(ifr)); - ifr.ifra_addr = *ifa->ifa_addr; - if (ifa->ifa_dstaddr) - ifr.ifra_broadaddr = *ifa->ifa_dstaddr; - if (in_control(NULL, SIOCDIFADDR, (caddr_t)&ifr, ifp, - NULL) == 0) - continue; - } -#endif /* INET */ -#ifdef INET6 - if (ifa->ifa_addr && ifa->ifa_addr->sa_family == AF_INET6) { - in6_purgeaddr(ifa); - /* ifp_addrhead is already updated */ - continue; - } -#endif /* INET6 */ - TAILQ_REMOVE(&ifp->if_addrhead, ifa, ifa_link); - IFAFREE(ifa); - } + if_purgeaddrs(ifp); #ifdef INET6 /* diff --git a/sys/net/if_tap.c b/sys/net/if_tap.c index 232c96d..a807bd5 100644 --- a/sys/net/if_tap.c +++ b/sys/net/if_tap.c @@ -31,7 +31,7 @@ */ /* - * $FreeBSD: src/sys/net/if_tap.c,v 1.53 2005/05/04 18:55:02 emax Exp $ + * $FreeBSD: src/sys/net/if_tap.c,v 1.54 2005/05/25 13:52:03 peadar Exp $ * $Id: if_tap.c,v 0.21 2000/07/23 21:46:02 max Exp $ */ @@ -408,6 +408,7 @@ tapclose(dev, foo, bar, td) int bar; struct thread *td; { + struct ifaddr *ifa; struct tap_softc *tp = dev->si_drv1; struct ifnet *ifp = &tp->tap_if; int s; @@ -426,24 +427,10 @@ tapclose(dev, foo, bar, td) s = splimp(); if_down(ifp); if (ifp->if_flags & IFF_RUNNING) { - /* find internet addresses and delete routes */ - struct ifaddr *ifa = NULL; - - /* In desparate need of ifaddr locking. */ TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { - if (ifa->ifa_addr->sa_family == AF_INET) { - rtinit(ifa, (int)RTM_DELETE, 0); - - /* remove address from interface */ - bzero(ifa->ifa_addr, - sizeof(*(ifa->ifa_addr))); - bzero(ifa->ifa_dstaddr, - sizeof(*(ifa->ifa_dstaddr))); - bzero(ifa->ifa_netmask, - sizeof(*(ifa->ifa_netmask))); - } + rtinit(ifa, (int)RTM_DELETE, 0); } - + if_purgeaddrs(ifp); ifp->if_flags &= ~IFF_RUNNING; } splx(s); diff --git a/sys/net/if_var.h b/sys/net/if_var.h index ab8d389..6d9cbed 100644 --- a/sys/net/if_var.h +++ b/sys/net/if_var.h @@ -27,7 +27,7 @@ * SUCH DAMAGE. * * From: @(#)if.h 8.1 (Berkeley) 6/10/93 - * $FreeBSD: src/sys/net/if_var.h,v 1.95 2005/04/20 09:30:54 glebius Exp $ + * $FreeBSD: src/sys/net/if_var.h,v 1.96 2005/05/25 13:52:03 peadar Exp $ */ #ifndef _NET_IF_VAR_H_ @@ -629,6 +629,7 @@ int if_allmulti(struct ifnet *, int); void if_attach(struct ifnet *); int if_delmulti(struct ifnet *, struct sockaddr *); void if_detach(struct ifnet *); +void if_purgeaddrs(struct ifnet *); void if_down(struct ifnet *); void if_initname(struct ifnet *, const char *, int); void if_link_state_change(struct ifnet *, int);
Attachment:
pgp00008.pgp
Description: PGP signature