git: bbce80f3efcb - stable/13 - MFC 2290dfb40fce:

From: Ryan Stone <rstone_at_FreeBSD.org>
Date: Fri, 25 Feb 2022 19:55:28 UTC
The branch stable/13 has been updated by rstone:

URL: https://cgit.FreeBSD.org/src/commit/?id=bbce80f3efcb1333ef661ade6b78ecd190fa32df

commit bbce80f3efcb1333ef661ade6b78ecd190fa32df
Author:     Ryan Stone <rstone@FreeBSD.org>
AuthorDate: 2021-05-19 19:10:03 +0000
Commit:     Ryan Stone <rstone@FreeBSD.org>
CommitDate: 2022-02-25 19:49:33 +0000

    MFC 2290dfb40fce:
    
    Enter the net epoch before calling ip6_setpktopts
    
    ip6_setpktopts() can look up ifnets via ifnet_by_index(), which
    is only safe in the net epoch.  Ensure that callers are in the net
    epoch before calling this function.
    
    Sponsored by: Dell EMC Isilon
    MFC after: 4 weeks
    Reviewed by: donner, kp
    Differential Revision: https://reviews.freebsd.org/D30630
    
    (cherry picked from commit 2290dfb40fce0ab46d91244282014173c7316e42)
---
 sys/netinet6/ip6_output.c  | 10 ++++++++++
 sys/netinet6/raw_ip6.c     |  8 ++++++--
 sys/netinet6/udp6_usrreq.c |  9 ++-------
 3 files changed, 18 insertions(+), 9 deletions(-)

diff --git a/sys/netinet6/ip6_output.c b/sys/netinet6/ip6_output.c
index 877d9db508c7..3c8811ca1af9 100644
--- a/sys/netinet6/ip6_output.c
+++ b/sys/netinet6/ip6_output.c
@@ -2488,6 +2488,7 @@ ip6_pcbopts(struct ip6_pktopts **pktopt, struct mbuf *m,
 	struct ip6_pktopts *opt = *pktopt;
 	int error = 0;
 	struct thread *td = sopt->sopt_td;
+	struct epoch_tracker et;
 
 	/* turn off any old options. */
 	if (opt) {
@@ -2515,12 +2516,15 @@ ip6_pcbopts(struct ip6_pktopts **pktopt, struct mbuf *m,
 	}
 
 	/*  set options specified by user. */
+	NET_EPOCH_ENTER(et);
 	if ((error = ip6_setpktopts(m, opt, NULL, (td != NULL) ?
 	    td->td_ucred : NULL, so->so_proto->pr_protocol)) != 0) {
 		ip6_clearpktopts(opt, -1); /* XXX: discard all options */
 		free(opt, M_IP6OPT);
+		NET_EPOCH_EXIT(et);
 		return (error);
 	}
+	NET_EPOCH_EXIT(et);
 	*pktopt = opt;
 	return (0);
 }
@@ -2816,6 +2820,12 @@ ip6_setpktopts(struct mbuf *control, struct ip6_pktopts *opt,
 	if (control == NULL || opt == NULL)
 		return (EINVAL);
 
+	/*
+	 * ip6_setpktopt can call ifnet_by_index(), so it's imperative that we are
+	 * in the net epoch here.
+	 */
+	NET_EPOCH_ASSERT();
+
 	ip6_initpktopts(opt);
 	if (stickyopt) {
 		int error;
diff --git a/sys/netinet6/raw_ip6.c b/sys/netinet6/raw_ip6.c
index 3e3df65a0e12..aaba91c6d5e7 100644
--- a/sys/netinet6/raw_ip6.c
+++ b/sys/netinet6/raw_ip6.c
@@ -419,9 +419,13 @@ rip6_output(struct mbuf *m, struct socket *so, ...)
 	INP_WLOCK(inp);
 
 	if (control != NULL) {
-		if ((error = ip6_setpktopts(control, &opt,
+		NET_EPOCH_ENTER(et);
+		error = ip6_setpktopts(control, &opt,
 		    inp->in6p_outputopts, so->so_cred,
-		    so->so_proto->pr_protocol)) != 0) {
+		    so->so_proto->pr_protocol);
+		NET_EPOCH_EXIT(et);
+
+		if (error != 0) {
 			goto bad;
 		}
 		optp = &opt;
diff --git a/sys/netinet6/udp6_usrreq.c b/sys/netinet6/udp6_usrreq.c
index 816e3bdd2850..6ee2abc4ea1b 100644
--- a/sys/netinet6/udp6_usrreq.c
+++ b/sys/netinet6/udp6_usrreq.c
@@ -810,21 +810,16 @@ udp6_output(struct socket *so, int flags_arg, struct mbuf *m,
 		return (EINVAL);
 	}
 
+	NET_EPOCH_ENTER(et);
 	if (control) {
 		if ((error = ip6_setpktopts(control, &opt,
 		    inp->in6p_outputopts, td->td_ucred, nxt)) != 0) {
-			INP_UNLOCK(inp);
-			ip6_clearpktopts(&opt, -1);
-			if (control)
-				m_freem(control);
-			m_freem(m);
-			return (error);
+			goto release;
 		}
 		optp = &opt;
 	} else
 		optp = inp->in6p_outputopts;
 
-	NET_EPOCH_ENTER(et);
 	if (sin6) {
 		/*
 		 * Since we saw no essential reason for calling in_pcbconnect,