aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Johnston <markj@FreeBSD.org>2020-03-19 21:38:52 +0000
committerMark Johnston <markj@FreeBSD.org>2020-03-19 21:38:52 +0000
commite02582d1ae44dfc7ae009481ce12930ccf662142 (patch)
tree6039a4e3b0319f09e741e76cb01fb805f7f858f6
parent27bae6150a9fd352796b5ff775eb464a2cf6dac9 (diff)
downloadsrc-e02582d1ae44dfc7ae009481ce12930ccf662142.tar.gz
src-e02582d1ae44dfc7ae009481ce12930ccf662142.zip
Fix synchronization in the IPV6_2292PKTOPTIONS set handler.
The inpcb needs to be locked when we update output packet options. Otherwise it is possible for the IPV6_2292PKTOPTIONS handler to free packet option structures while another thread is reading or updating them. Note that the option handler is still kind of broken. For instance it frees all options before performing privilege checks for individual options. However, this can be fixed separately. Reported by: syzbot+52eb0fd4ddc119787f9d@syzkaller.appspotmail.com Reviewed by: bz, tuexen MFC after: 2 weeks Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D24125
Notes
Notes: svn path=/head/; revision=359154
-rw-r--r--sys/netinet6/ip6_output.c13
1 files changed, 9 insertions, 4 deletions
diff --git a/sys/netinet6/ip6_output.c b/sys/netinet6/ip6_output.c
index 1d512cb26c61..a171c0eac5a3 100644
--- a/sys/netinet6/ip6_output.c
+++ b/sys/netinet6/ip6_output.c
@@ -1694,8 +1694,10 @@ ip6_ctloutput(struct socket *so, struct sockopt *sopt)
error = soopt_mcopyin(sopt, m); /* XXX */
if (error != 0)
break;
- error = ip6_pcbopts(&inp->in6p_outputopts,
- m, so, sopt);
+ INP_WLOCK(inp);
+ error = ip6_pcbopts(&inp->in6p_outputopts, m,
+ so, sopt);
+ INP_WUNLOCK(inp);
m_freem(m); /* XXX */
break;
}
@@ -2458,8 +2460,11 @@ ip6_pcbopts(struct ip6_pktopts **pktopt, struct mbuf *m,
printf("ip6_pcbopts: all specified options are cleared.\n");
#endif
ip6_clearpktopts(opt, -1);
- } else
- opt = malloc(sizeof(*opt), M_IP6OPT, M_WAITOK);
+ } else {
+ opt = malloc(sizeof(*opt), M_IP6OPT, M_NOWAIT);
+ if (opt == NULL)
+ return (ENOMEM);
+ }
*pktopt = NULL;
if (!m || m->m_len == 0) {