Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 23 Dec 2011 15:08:52 -0500
From:      John Baldwin <jhb@freebsd.org>
To:        net@freebsd.org
Cc:        Bjoern Zeeb <bz@freebsd.org>
Subject:   [PATCH] Use of unreferenced ifa in in6
Message-ID:  <201112231508.52861.jhb@freebsd.org>

next in thread | raw e-mail | index | archive | help
The code to handle the SIOCGLIFADDR and SIOCDLIFADDR ioctls in 
in6_lifaddr_ioctl() does not grab a reference to an ifnet address structure 
that it uses after dropping the IF_ADDR_LOCK().  Based on other code that uses 
a similar pattern of finding an ifa while under the lock and then using it 
after dropping the lock, I believe it should be acquiring a reference on the 
ifa and then dropping that reference when it is done using the ifa.  This 
(untested) patch should fix this I believe:

Index: in6.c
===================================================================
--- in6.c	(revision 228777)
+++ in6.c	(working copy)
@@ -1767,6 +1767,8 @@ in6_lifaddr_ioctl(struct socket *so, u_long cmd, c
 			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_long cmd, c
 			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_long cmd, c
 			    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_long cmd, c
 			    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);
 		}


-- 
John Baldwin



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201112231508.52861.jhb>