svn commit: r366795 - head/sys/netinet

Alexander V. Chernikov melifaro at FreeBSD.org
Sat Oct 17 20:33:10 UTC 2020


Author: melifaro
Date: Sat Oct 17 20:33:09 2020
New Revision: 366795
URL: https://svnweb.freebsd.org/changeset/base/366795

Log:
  Fix sleepq_add panic happening with too wide net epoch in mcast control.
  
  PR:		250413
  Reported by:	Christopher Hall <hsw at bitmark.com>
  Reviewed by:	ae
  Differential Revision:	https://reviews.freebsd.org/D26827

Modified:
  head/sys/netinet/in_mcast.c

Modified: head/sys/netinet/in_mcast.c
==============================================================================
--- head/sys/netinet/in_mcast.c	Sat Oct 17 17:31:06 2020	(r366794)
+++ head/sys/netinet/in_mcast.c	Sat Oct 17 20:33:09 2020	(r366795)
@@ -1905,7 +1905,7 @@ inp_getmoptions(struct inpcb *inp, struct sockopt *sop
  * this in order to allow groups to be joined when the routing
  * table has not yet been populated during boot.
  *
- * Returns NULL if no ifp could be found.
+ * Returns NULL if no ifp could be found, otherwise return referenced ifp.
  *
  * FUTURE: Implement IPv4 source-address selection.
  */
@@ -1926,13 +1926,16 @@ inp_lookup_mcast_ifp(const struct inpcb *inp,
 	if (!in_nullhost(ina)) {
 		IN_IFADDR_RLOCK(&in_ifa_tracker);
 		INADDR_TO_IFP(ina, ifp);
+		if (ifp != NULL)
+			if_ref(ifp);
 		IN_IFADDR_RUNLOCK(&in_ifa_tracker);
 	} else {
-		fibnum = inp ? inp->inp_inc.inc_fibnum : 0;
-		nh = fib4_lookup(fibnum, gsin->sin_addr, 0, 0, 0);
-		if (nh != NULL)
+		fibnum = inp ? inp->inp_inc.inc_fibnum : RT_DEFAULT_FIB;
+		nh = fib4_lookup(fibnum, gsin->sin_addr, 0, NHR_NONE, 0);
+		if (nh != NULL) {
 			ifp = nh->nh_ifp;
-		else {
+			if_ref(ifp);
+		} else {
 			struct in_ifaddr *ia;
 			struct ifnet *mifp;
 
@@ -1943,6 +1946,7 @@ inp_lookup_mcast_ifp(const struct inpcb *inp,
 				if (!(mifp->if_flags & IFF_LOOPBACK) &&
 				     (mifp->if_flags & IFF_MULTICAST)) {
 					ifp = mifp;
+					if_ref(ifp);
 					break;
 				}
 			}
@@ -1966,6 +1970,7 @@ inp_join_group(struct inpcb *inp, struct sockopt *sopt
 	struct ip_moptions		*imo;
 	struct in_multi			*inm;
 	struct in_msource		*lims;
+	struct epoch_tracker		 et;
 	int				 error, is_new;
 
 	ifp = NULL;
@@ -1997,9 +2002,10 @@ inp_join_group(struct inpcb *inp, struct sockopt *sopt
 		if (!IN_MULTICAST(ntohl(gsa->sin.sin_addr.s_addr)))
 			return (EINVAL);
 
+		NET_EPOCH_ENTER(et);
 		if (sopt->sopt_valsize == sizeof(struct ip_mreqn) &&
 		    mreqn.imr_ifindex != 0)
-			ifp = ifnet_byindex(mreqn.imr_ifindex);
+			ifp = ifnet_byindex_ref(mreqn.imr_ifindex);
 		else
 			ifp = inp_lookup_mcast_ifp(inp, &gsa->sin,
 			    mreqn.imr_address);
@@ -2023,6 +2029,7 @@ inp_join_group(struct inpcb *inp, struct sockopt *sopt
 
 		ssa->sin.sin_addr = mreqs.imr_sourceaddr;
 
+		NET_EPOCH_ENTER(et);
 		ifp = inp_lookup_mcast_ifp(inp, &gsa->sin,
 		    mreqs.imr_interface);
 		CTR3(KTR_IGMPV3, "%s: imr_interface = 0x%08x, ifp = %p",
@@ -2065,7 +2072,8 @@ inp_join_group(struct inpcb *inp, struct sockopt *sopt
 
 		if (gsr.gsr_interface == 0 || V_if_index < gsr.gsr_interface)
 			return (EADDRNOTAVAIL);
-		ifp = ifnet_byindex(gsr.gsr_interface);
+		NET_EPOCH_ENTER(et);
+		ifp = ifnet_byindex_ref(gsr.gsr_interface);
 		break;
 
 	default:
@@ -2074,9 +2082,13 @@ inp_join_group(struct inpcb *inp, struct sockopt *sopt
 		return (EOPNOTSUPP);
 		break;
 	}
+	NET_EPOCH_EXIT(et);
 
-	if (ifp == NULL || (ifp->if_flags & IFF_MULTICAST) == 0)
+	if (ifp == NULL || (ifp->if_flags & IFF_MULTICAST) == 0) {
+		if (ifp != NULL)
+			if_rele(ifp);
 		return (EADDRNOTAVAIL);
+	}
 
 	IN_MULTI_LOCK();
 
@@ -2265,6 +2277,7 @@ out_inp_unlocked:
 		}
 		ip_mfilter_free(imf);
 	}
+	if_rele(ifp);
 	return (error);
 }
 
@@ -2740,7 +2753,6 @@ inp_setmoptions(struct inpcb *inp, struct sockopt *sop
 {
 	struct ip_moptions	*imo;
 	int			 error;
-	struct epoch_tracker	et;
 
 	error = 0;
 
@@ -2847,9 +2859,7 @@ inp_setmoptions(struct inpcb *inp, struct sockopt *sop
 	case IP_ADD_SOURCE_MEMBERSHIP:
 	case MCAST_JOIN_GROUP:
 	case MCAST_JOIN_SOURCE_GROUP:
-		NET_EPOCH_ENTER(et);
 		error = inp_join_group(inp, sopt);
-		NET_EPOCH_EXIT(et);
 		break;
 
 	case IP_DROP_MEMBERSHIP:


More information about the svn-src-all mailing list