kernel panic

Matthew Dillon dillon at apollo.backplane.com
Mon Sep 3 14:12:49 PDT 2007


    I think there a ref-counting problem with the ifaddr structure.  This
    structure is embedded in the ifnet structure and used all over the place.
    I can't find the exact cause so here's a patch which will hopefully
    force a panic (with INVARIANTS turned on of course) if any attempt is
    made to free the structure before it has been removed from the address
    list.  If we can catch it here it should become obvious where the bug
    is.

						-Matt


Index: net/if_var.h
===================================================================
RCS file: /cvs/src/sys/net/if_var.h,v
retrieving revision 1.39
diff -u -p -r1.39 if_var.h
--- net/if_var.h	16 Aug 2007 20:03:57 -0000	1.39
+++ net/if_var.h	3 Sep 2007 21:02:41 -0000
@@ -375,6 +375,7 @@ 		(struct ifaddr *, struct sockaddr *);
 
 };
 #define	IFA_ROUTE	RTF_UP		/* route installed */
+#define	IFA_XLIST	RTF_XLIST	/* route installed in in_ifaddrhead */
 
 /* for compatibility with other BSDs */
 #define	ifa_list	ifa_link
@@ -429,6 +430,7 @@ 	++_ifa->ifa_refcnt;
 }
 
 #include <sys/malloc.h>
+#include <net/route.h>
 
 MALLOC_DECLARE(M_IFADDR);
 MALLOC_DECLARE(M_IFMADDR);
@@ -436,10 +438,12 @@ 
 static __inline void
 IFAFREE(struct ifaddr *_ifa)
 {
-	if (_ifa->ifa_refcnt <= 0)
+	if (_ifa->ifa_refcnt <= 0) {
+		KKASSERT((_ifa->ifa_flags & IFA_XLIST) == 0);
 		kfree(_ifa, M_IFADDR);
-	else
+	} else {
 		_ifa->ifa_refcnt--;
+	}
 }
 
 extern	struct ifnethead ifnet;
Index: net/route.h
===================================================================
RCS file: /cvs/src/sys/net/route.h,v
retrieving revision 1.21
diff -u -p -r1.21 route.h
--- net/route.h	4 Mar 2007 18:51:59 -0000	1.21
+++ net/route.h	3 Sep 2007 21:01:50 -0000
@@ -203,7 +203,8 @@ #define RTF_PINNED	0x100000	/* future us
 #define	RTF_LOCAL	0x200000	/* route represents a local address */
 #define	RTF_BROADCAST	0x400000	/* route represents a bcast address */
 #define	RTF_MULTICAST	0x800000	/* route represents a mcast address */
-					/* 0x1000000 and up unassigned */
+#define RTF_XLIST	0x1000000	/* on auxillary list (sanity check) */
+					/* 0x2000000 and up unassigned */
 
 /*
  * Routing statistics.
Index: netinet/in.c
===================================================================
RCS file: /cvs/src/sys/netinet/in.c,v
retrieving revision 1.20
diff -u -p -r1.20 in.c
--- netinet/in.c	30 Sep 2006 22:38:21 -0000	1.20
+++ netinet/in.c	3 Sep 2007 21:00:54 -0000
@@ -274,11 +274,15 @@ 			bzero(ia, sizeof *ia);
 			/*
 			 * Protect from ipintr() traversing address list
 			 * while we're modifying it.
+			 *
+			 * IFA_XLIST applies to the in_ifaddrhead list,
+			 * set it when the ifa has been added.
 			 */
 			crit_enter();
 			
 			TAILQ_INSERT_TAIL(&in_ifaddrhead, ia, ia_link);
 			ifa = &ia->ia_ifa;
+			ifa->ifa_flags |= IFA_XLIST;
 			TAILQ_INSERT_TAIL(&ifp->if_addrhead, ifa, ifa_link);
 
 			ifa->ifa_addr = (struct sockaddr *)&ia->ia_addr;
@@ -444,10 +448,14 @@ 
 	/*
 	 * Protect from ipintr() traversing address list while we're modifying
 	 * it.
+	 *
+	 * IFA_XLIST applies to the in_ifaddrhead list, clear it when the ifa
+	 * has been removed.
 	 */
 	lwkt_serialize_enter(ifp->if_serializer);
 	TAILQ_REMOVE(&ifp->if_addrhead, &ia->ia_ifa, ifa_link);
 	TAILQ_REMOVE(&in_ifaddrhead, ia, ia_link);
+	ia->ia_ifa.ifa_flags &= ~IFA_XLIST;
 	LIST_REMOVE(ia, ia_hash);
 	IFAFREE(&ia->ia_ifa);
 	lwkt_serialize_exit(ifp->if_serializer);





More information about the Bugs mailing list