Index | Thread | Search

From:
Vitaliy Makkoveev <mvs@openbsd.org>
Subject:
ip6_sysctl(): push netlock down to mrt6_sysctl_mif()
To:
Alexander Bluhm <bluhm@openbsd.org>, tech@openbsd.org
Date:
Thu, 24 Jul 2025 23:18:15 +0300

Download raw body.

Thread
Except the delivered data, it is the same as mrt_sysctl_vif(). So link
the network interfaces to the temporary list protected by
`if_tmplist_lock' rwlock(9) to avoid copyout() with netlock held. Also
use shared netlock instead of exclusive.

Index: sys/netinet6/ip6_input.c
===================================================================
RCS file: /cvs/src/sys/netinet6/ip6_input.c,v
retrieving revision 1.285
diff -u -p -r1.285 ip6_input.c
--- sys/netinet6/ip6_input.c	24 Jul 2025 18:02:19 -0000	1.285
+++ sys/netinet6/ip6_input.c	24 Jul 2025 20:13:22 -0000
@@ -1516,10 +1516,7 @@ ip6_sysctl(int *name, u_int namelen, voi
 	case IPV6CTL_MRTMIF:
 		if (newp)
 			return (EPERM);
-		NET_LOCK();
-		error = mrt6_sysctl_mif(oldp, oldlenp);
-		NET_UNLOCK();
-		return (error);
+		return (mrt6_sysctl_mif(oldp, oldlenp));
 	case IPV6CTL_MRTMFC:
 		if (newp)
 			return (EPERM);
Index: sys/netinet6/ip6_mroute.c
===================================================================
RCS file: /cvs/src/sys/netinet6/ip6_mroute.c,v
retrieving revision 1.151
diff -u -p -r1.151 ip6_mroute.c
--- sys/netinet6/ip6_mroute.c	23 Jul 2025 18:58:38 -0000	1.151
+++ sys/netinet6/ip6_mroute.c	24 Jul 2025 20:13:22 -0000
@@ -304,18 +304,36 @@ get_mif6_cnt(struct sioc_mif_req6 *req, 
 int
 mrt6_sysctl_mif(void *oldp, size_t *oldlenp)
 {
+	TAILQ_HEAD(, ifnet) if_tmplist =
+	    TAILQ_HEAD_INITIALIZER(if_tmplist);
 	struct ifnet *ifp;
 	caddr_t where = oldp;
 	size_t needed, given;
 	struct mif6 *mifp;
 	struct mif6info minfo;
+	int error = 0;
 
 	given = *oldlenp;
 	needed = 0;
 	memset(&minfo, 0, sizeof minfo);
+
+	rw_enter_write(&if_tmplist_lock);
+	NET_LOCK_SHARED();
+
 	TAILQ_FOREACH(ifp, &ifnetlist, if_list) {
-		if ((mifp = (struct mif6 *)ifp->if_mcast6) == NULL)
+		if (ifp->if_mcast6 != NULL) {
+			if_ref(ifp);
+			TAILQ_INSERT_TAIL(&if_tmplist, ifp, if_tmplist);
+		}
+	}
+	NET_UNLOCK_SHARED();
+
+	TAILQ_FOREACH (ifp, &if_tmplist, if_tmplist) {
+		NET_LOCK_SHARED();
+		if ((mifp = (struct mif6 *)ifp->if_mcast6) == NULL) {
+			NET_UNLOCK_SHARED();
 			continue;
+		}
 
 		minfo.m6_mifi = mifp->m6_mifi;
 		minfo.m6_flags = mifp->m6_flags;
@@ -326,6 +344,7 @@ mrt6_sysctl_mif(void *oldp, size_t *oldl
 		minfo.m6_bytes_in = mifp->m6_bytes_in;
 		minfo.m6_bytes_out = mifp->m6_bytes_out;
 		minfo.m6_rate_limit = mifp->m6_rate_limit;
+		NET_UNLOCK_SHARED();
 
 		needed += sizeof(minfo);
 		if (where && needed <= given) {
@@ -333,10 +352,21 @@ mrt6_sysctl_mif(void *oldp, size_t *oldl
 
 			error = copyout(&minfo, where, sizeof(minfo));
 			if (error)
-				return (error);
+				break;
 			where += sizeof(minfo);
 		}
 	}
+
+	while ((ifp = TAILQ_FIRST(&if_tmplist))) {
+		TAILQ_REMOVE(&if_tmplist, ifp, if_tmplist);
+		if_put(ifp);
+	}
+
+	rw_exit_write(&if_tmplist_lock);
+
+	if (error)
+		return (error);
+
 	if (where) {
 		*oldlenp = needed;
 		if (given < needed)