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);

Reply via email to