Author: rwatson
Date: Sat Jun 27 11:05:53 2009
New Revision: 195102
URL: http://svn.freebsd.org/changeset/base/195102

Log:
  In in6_update_ifa(), jump to 'cleanup' rather than returning directly
  in one additional case, avoiding an ifaddr reference leak.
  
  Defer releasing the in6_ifaddr's in6_ifaddrhead reference until the
  end of in6_unlink_ifa(), as callers are inconsistent regarding whether
  or not they hold a reference across the call.  This avoids using the
  ifaddr after it may have been freed.
  
  Reported by:  tegge
  Reviewed by:  tegge
  Approved by:  re (blanket)
  MFC after:    6 weeks

Modified:
  head/sys/netinet6/in6.c

Modified: head/sys/netinet6/in6.c
==============================================================================
--- head/sys/netinet6/in6.c     Sat Jun 27 10:45:58 2009        (r195101)
+++ head/sys/netinet6/in6.c     Sat Jun 27 11:05:53 2009        (r195102)
@@ -970,8 +970,7 @@ in6_update_ifa(struct ifnet *ifp, struct
                            "%s on %s (errno=%d)\n",
                            ip6_sprintf(ip6buf, &llsol), if_name(ifp),
                            error));
-                       in6_purgeaddr((struct ifaddr *)ia);
-                       return (error);
+                       goto cleanup;
                }
                LIST_INSERT_HEAD(&ia->ia6_memberships,
                    imm, i6mm_chain);
@@ -1378,10 +1377,14 @@ in6_unlink_ifa(struct in6_ifaddr *ia, st
        IF_ADDR_UNLOCK(ifp);
        ifa_free(&ia->ia_ifa);                  /* if_addrhead */
 
+       /*
+        * Defer the release of what might be the last reference to the
+        * in6_ifaddr so that it can't be freed before the remainder of the
+        * cleanup.
+        */
        IN6_IFADDR_WLOCK();
        TAILQ_REMOVE(&V_in6_ifaddrhead, ia, ia_link);
        IN6_IFADDR_WUNLOCK();
-       ifa_free(&ia->ia_ifa);                  /* in6_ifaddrhead */
 
        /*
         * Release the reference to the base prefix.  There should be a
@@ -1404,7 +1407,7 @@ in6_unlink_ifa(struct in6_ifaddr *ia, st
        if ((ia->ia6_flags & IN6_IFF_AUTOCONF)) {
                pfxlist_onlink_check();
        }
-
+       ifa_free(&ia->ia_ifa);                  /* in6_ifaddrhead */
        splx(s);
 }
 
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to