Author: jhb
Date: Tue Jan  3 19:44:36 2012
New Revision: 229414
URL: http://svn.freebsd.org/changeset/base/229414

Log:
  Grab a reference on the matching interface address (ifa) in the handling
  of the SIOC[DG]LIFADDR icotls before dropping the IF_ADDR_LOCK() and
  release the reference after using it.  This prevents the address from
  being potentially freed out from under the ioctl handler.
  
  Reviewed by:  bz
  MFC after:    1 week

Modified:
  head/sys/netinet6/in6.c

Modified: head/sys/netinet6/in6.c
==============================================================================
--- head/sys/netinet6/in6.c     Tue Jan  3 19:41:36 2012        (r229413)
+++ head/sys/netinet6/in6.c     Tue Jan  3 19:44:36 2012        (r229414)
@@ -1767,6 +1767,8 @@ in6_lifaddr_ioctl(struct socket *so, u_l
                        if (IN6_ARE_ADDR_EQUAL(&candidate, &match))
                                break;
                }
+               if (ifa != NULL)
+                       ifa_ref(ifa);
                IF_ADDR_UNLOCK(ifp);
                if (!ifa)
                        return EADDRNOTAVAIL;
@@ -1779,16 +1781,20 @@ in6_lifaddr_ioctl(struct socket *so, u_l
                        bcopy(&ia->ia_addr, &iflr->addr, ia->ia_addr.sin6_len);
                        error = sa6_recoverscope(
                            (struct sockaddr_in6 *)&iflr->addr);
-                       if (error != 0)
+                       if (error != 0) {
+                               ifa_free(ifa);
                                return (error);
+                       }
 
                        if ((ifp->if_flags & IFF_POINTOPOINT) != 0) {
                                bcopy(&ia->ia_dstaddr, &iflr->dstaddr,
                                    ia->ia_dstaddr.sin6_len);
                                error = sa6_recoverscope(
                                    (struct sockaddr_in6 *)&iflr->dstaddr);
-                               if (error != 0)
+                               if (error != 0) {
+                                       ifa_free(ifa);
                                        return (error);
+                               }
                        } else
                                bzero(&iflr->dstaddr, sizeof(iflr->dstaddr));
 
@@ -1796,6 +1802,7 @@ in6_lifaddr_ioctl(struct socket *so, u_l
                            in6_mask2len(&ia->ia_prefixmask.sin6_addr, NULL);
 
                        iflr->flags = ia->ia6_flags;    /* XXX */
+                       ifa_free(ifa);
 
                        return 0;
                } else {
@@ -1819,6 +1826,7 @@ in6_lifaddr_ioctl(struct socket *so, u_l
                            ia->ia_prefixmask.sin6_len);
 
                        ifra.ifra_flags = ia->ia6_flags;
+                       ifa_free(ifa);
                        return in6_control(so, SIOCDIFADDR_IN6, (caddr_t)&ifra,
                            ifp, td);
                }
_______________________________________________
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