aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRyan Stone <rstone@FreeBSD.org>2021-05-19 19:10:03 +0000
committerRyan Stone <rstone@FreeBSD.org>2021-06-04 17:18:11 +0000
commit2290dfb40fce0ab46d91244282014173c7316e42 (patch)
tree38cb467bb53387ea833019eb80dc21e1bf6a541d
parentdab84426a68d43efaede62ccf86ca3ef852f8ae3 (diff)
downloadsrc-2290dfb40fce0ab46d91244282014173c7316e42.tar.gz
src-2290dfb40fce0ab46d91244282014173c7316e42.zip
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
-rw-r--r--sys/netinet6/ip6_output.c10
-rw-r--r--sys/netinet6/raw_ip6.c8
-rw-r--r--sys/netinet6/udp6_usrreq.c9
3 files changed, 18 insertions, 9 deletions
diff --git a/sys/netinet6/ip6_output.c b/sys/netinet6/ip6_output.c
index 2b49a9f7c351..71c5c4e5a501 100644
--- a/sys/netinet6/ip6_output.c
+++ b/sys/netinet6/ip6_output.c
@@ -2496,6 +2496,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) {
@@ -2523,12 +2524,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);
}
@@ -2824,6 +2828,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 a369abb04bfc..ad64429b5890 100644
--- a/sys/netinet6/raw_ip6.c
+++ b/sys/netinet6/raw_ip6.c
@@ -417,9 +417,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 7c573d095d77..5841988f6113 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,