diff options
author | Mark Johnston <markj@FreeBSD.org> | 2020-03-19 21:38:52 +0000 |
---|---|---|
committer | Mark Johnston <markj@FreeBSD.org> | 2020-03-19 21:38:52 +0000 |
commit | e02582d1ae44dfc7ae009481ce12930ccf662142 (patch) | |
tree | 6039a4e3b0319f09e741e76cb01fb805f7f858f6 | |
parent | 27bae6150a9fd352796b5ff775eb464a2cf6dac9 (diff) | |
download | src-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.c | 13 |
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) { |