fix interface address list traversal in if_detach():
The code was assuming that interface addresses are removed one-by-one. With IPv6 and multicasts, removal of one address can remove other addresses as side effect, which caused accesses of free()d memory.
This commit is contained in:
parent
79bf8521a5
commit
14332cf998
15
sys/net/if.c
15
sys/net/if.c
|
@ -1,4 +1,4 @@
|
||||||
/* $NetBSD: if.c,v 1.133 2003/11/10 20:03:29 jonathan Exp $ */
|
/* $NetBSD: if.c,v 1.134 2003/11/11 20:33:46 drochner Exp $ */
|
||||||
|
|
||||||
/*-
|
/*-
|
||||||
* Copyright (c) 1999, 2000, 2001 The NetBSD Foundation, Inc.
|
* Copyright (c) 1999, 2000, 2001 The NetBSD Foundation, Inc.
|
||||||
|
@ -97,7 +97,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <sys/cdefs.h>
|
#include <sys/cdefs.h>
|
||||||
__KERNEL_RCSID(0, "$NetBSD: if.c,v 1.133 2003/11/10 20:03:29 jonathan Exp $");
|
__KERNEL_RCSID(0, "$NetBSD: if.c,v 1.134 2003/11/11 20:33:46 drochner Exp $");
|
||||||
|
|
||||||
#include "opt_inet.h"
|
#include "opt_inet.h"
|
||||||
|
|
||||||
|
@ -544,7 +544,7 @@ if_detach(ifp)
|
||||||
struct ifnet *ifp;
|
struct ifnet *ifp;
|
||||||
{
|
{
|
||||||
struct socket so;
|
struct socket so;
|
||||||
struct ifaddr *ifa, *next;
|
struct ifaddr *ifa, **ifap;
|
||||||
#ifdef IFAREF_DEBUG
|
#ifdef IFAREF_DEBUG
|
||||||
struct ifaddr *last_ifa = NULL;
|
struct ifaddr *last_ifa = NULL;
|
||||||
#endif
|
#endif
|
||||||
|
@ -581,8 +581,8 @@ if_detach(ifp)
|
||||||
* Rip all the addresses off the interface. This should make
|
* Rip all the addresses off the interface. This should make
|
||||||
* all of the routes go away.
|
* all of the routes go away.
|
||||||
*/
|
*/
|
||||||
for (ifa = TAILQ_FIRST(&ifp->if_addrlist); ifa; ifa = next) {
|
ifap = &TAILQ_FIRST(&ifp->if_addrlist); /* XXX abstraction violation */
|
||||||
next = TAILQ_NEXT(ifa, ifa_list);
|
while ((ifa = *ifap)) {
|
||||||
family = ifa->ifa_addr->sa_family;
|
family = ifa->ifa_addr->sa_family;
|
||||||
#ifdef IFAREF_DEBUG
|
#ifdef IFAREF_DEBUG
|
||||||
printf("if_detach: ifaddr %p, family %d, refcnt %d\n",
|
printf("if_detach: ifaddr %p, family %d, refcnt %d\n",
|
||||||
|
@ -591,8 +591,10 @@ if_detach(ifp)
|
||||||
panic("if_detach: loop detected");
|
panic("if_detach: loop detected");
|
||||||
last_ifa = ifa;
|
last_ifa = ifa;
|
||||||
#endif
|
#endif
|
||||||
if (family == AF_LINK)
|
if (family == AF_LINK) {
|
||||||
|
ifap = &TAILQ_NEXT(ifa, ifa_list);
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
dp = pffinddomain(family);
|
dp = pffinddomain(family);
|
||||||
#ifdef DIAGNOSTIC
|
#ifdef DIAGNOSTIC
|
||||||
if (dp == NULL)
|
if (dp == NULL)
|
||||||
|
@ -617,6 +619,7 @@ if_detach(ifp)
|
||||||
*/
|
*/
|
||||||
printf("if_detach: WARNING: AF %d not purged\n",
|
printf("if_detach: WARNING: AF %d not purged\n",
|
||||||
family);
|
family);
|
||||||
|
TAILQ_REMOVE(&ifp->if_addrlist, ifa, ifa_list);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue