Subject: fix for if_detach panic
To: None <tech-net@netbsd.org>
From: YAMAMOTO Takashi <yamt@mwd.biglobe.ne.jp>
List: tech-net
Date: 07/29/2004 08:17:51
--NextPart-20040729081302-0079400
Content-Type: Text/Plain; charset=us-ascii

hi,

the attached diff is to fix address leaks on ioctl error,
which causes a panic on if_detach.
("if_detach: no domain for AF 0")

- SIOCAIFADDR, SIOCSIFADDR: free an address on error.
- SIOCSIFNETMASK, SIOCSIFDSTADDR: reject operations for an interface which
  has no AF_INET addresses.
(partly from OpenBSD and FreeBSD.)

can anyone review it?  thanks.

YAMAMOTO Takashi

--NextPart-20040729081302-0079400
Content-Type: Text/Plain; charset=us-ascii
Content-Disposition: attachment; filename="a.diff"

Index: netinet/in.c
===================================================================
--- netinet/in.c	(revision 824)
+++ netinet/in.c	(revision 825)
@@ -326,6 +326,7 @@ in_control(so, cmd, data, ifp, p)
 	struct in_aliasreq *ifra = (struct in_aliasreq *)data;
 	struct sockaddr_in oldaddr;
 	int error, hostIsNew, maskIsNew;
+	int newifaddr = 0;
 
 	switch (cmd) {
 	case SIOCALIFADDR:
@@ -380,6 +381,10 @@ in_control(so, cmd, data, ifp, p)
 		if (cmd == SIOCGIFALIAS)
 			break;
 
+		if (ia == NULL &&
+		    (cmd == SIOCSIFNETMASK || cmd == SIOCSIFDSTADDR))
+			return (EADDRNOTAVAIL);
+
 		if (p == 0 || (error = suser(p->p_ucred, &p->p_acflag)))
 			return (EPERM);
 
@@ -404,6 +409,7 @@ in_control(so, cmd, data, ifp, p)
 			}
 			ia->ia_ifp = ifp;
 			LIST_INIT(&ia->ia_multiaddrs);
+			newifaddr = 1;
 		}
 		break;
 
@@ -420,6 +426,7 @@ in_control(so, cmd, data, ifp, p)
 			return (EADDRNOTAVAIL);
 		break;
 	}
+	error = 0;
 	switch (cmd) {
 
 	case SIOCGIFADDR:
@@ -473,19 +480,18 @@ in_control(so, cmd, data, ifp, p)
 			(void)pfil_run_hooks(&if_pfil,
 			    (struct mbuf **)SIOCSIFADDR, ifp, PFIL_IFADDR);
 #endif
-		return error;
+		break;
 
 	case SIOCSIFNETMASK:
 		in_ifscrub(ifp, ia);
 		ia->ia_sockmask = *satosin(&ifr->ifr_addr);
 		ia->ia_subnetmask = ia->ia_sockmask.sin_addr.s_addr;
 		error = in_ifinit(ifp, ia, NULL, 0);
-		return (error);
+		break;
 
 	case SIOCAIFADDR:
 		maskIsNew = 0;
 		hostIsNew = 1;
-		error = 0;
 		if (ia->ia_addr.sin_family == AF_INET) {
 			if (ifra->ifra_addr.sin_len == 0) {
 				ifra->ifra_addr = ia->ia_addr;
@@ -517,7 +523,7 @@ in_control(so, cmd, data, ifp, p)
 			(void)pfil_run_hooks(&if_pfil,
 			    (struct mbuf **)SIOCAIFADDR, ifp, PFIL_IFADDR);
 #endif
-		return (error);
+		break;
 
 	case SIOCGIFALIAS:
 		ifra->ifra_mask = ia->ia_sockmask;
@@ -530,7 +536,7 @@ in_control(so, cmd, data, ifp, p)
 		else
 			bzero(&ifra->ifra_broadaddr,
 			      sizeof(ifra->ifra_broadaddr));
-		return 0;
+		break;
 
 	case SIOCDIFADDR:
 		in_purgeaddr(&ia->ia_ifa, ifp);
@@ -543,7 +549,8 @@ in_control(so, cmd, data, ifp, p)
 #ifdef MROUTING
 	case SIOCGETVIFCNT:
 	case SIOCGETSGCNT:
-		return (mrt_ioctl(so, cmd, data));
+		error = mrt_ioctl(so, cmd, data);
+		break;
 #endif /* MROUTING */
 
 	default:
@@ -551,9 +558,15 @@ in_control(so, cmd, data, ifp, p)
 			return (EOPNOTSUPP);
 		error = (*ifp->if_ioctl)(ifp, cmd, data);
 		in_setmaxmtu();
-		return (error);
+		break;
 	}
-	return (0);
+
+	if (error && newifaddr) {
+		KASSERT(ia != NULL);
+		in_purgeaddr(&ia->ia_ifa, ifp);
+	}
+
+	return error;
 }
 
 void

--NextPart-20040729081302-0079400--