From 1ff6e7a8a8599946804b79ee98ac9ae4ec8950da Mon Sep 17 00:00:00 2001 From: "Bjoern A. Zeeb" Date: Wed, 24 Oct 2018 10:42:35 +0000 Subject: [PATCH] rip6_input() inp validation after epoch(9) After r335924 rip6_input() needs inp validation to avoid working on FREED inps. Apply the relevant bits from r335497,r335501 (rip_input() change) to the IPv6 counterpart. PR: 232194 Reviewed by: rgrimes, ae (,hps) MFC after: 3 days Differential Revision: https://reviews.freebsd.org/D17594 --- sys/netinet6/raw_ip6.c | 86 ++++++++++++++++++++++-------------------- 1 file changed, 45 insertions(+), 41 deletions(-) diff --git a/sys/netinet6/raw_ip6.c b/sys/netinet6/raw_ip6.c index 192d1b320e3c..3341a914c0e0 100644 --- a/sys/netinet6/raw_ip6.c +++ b/sys/netinet6/raw_ip6.c @@ -187,6 +187,45 @@ rip6_input(struct mbuf **mp, int *offp, int proto) if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr) && !IN6_ARE_ADDR_EQUAL(&in6p->in6p_faddr, &ip6->ip6_src)) continue; + if (last != NULL) { + struct mbuf *n = m_copym(m, 0, M_COPYALL, M_NOWAIT); + +#if defined(IPSEC) || defined(IPSEC_SUPPORT) + /* + * Check AH/ESP integrity. + */ + if (IPSEC_ENABLED(ipv6)) { + if (n != NULL && + IPSEC_CHECK_POLICY(ipv6, n, last) != 0) { + m_freem(n); + /* Do not inject data into pcb. */ + n = NULL; + } + } +#endif /* IPSEC */ + if (n) { + if (last->inp_flags & INP_CONTROLOPTS || + last->inp_socket->so_options & SO_TIMESTAMP) + ip6_savecontrol(last, n, &opts); + /* strip intermediate headers */ + m_adj(n, *offp); + if (sbappendaddr(&last->inp_socket->so_rcv, + (struct sockaddr *)&fromsa, + n, opts) == 0) { + m_freem(n); + if (opts) + m_freem(opts); + RIP6STAT_INC(rip6s_fullsock); + } else + sorwakeup(last->inp_socket); + opts = NULL; + } + INP_RUNLOCK(last); + last = NULL; + } + INP_RLOCK(in6p); + if (__predict_false(in6p->inp_flags2 & INP_FREED)) + goto skip_2; if (jailed_without_vnet(in6p->inp_cred)) { /* * Allow raw socket in jail to receive multicast; @@ -196,16 +235,14 @@ rip6_input(struct mbuf **mp, int *offp, int proto) if (!IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst) && prison_check_ip6(in6p->inp_cred, &ip6->ip6_dst) != 0) - continue; + goto skip_2; } - INP_RLOCK(in6p); if (in6p->in6p_cksum != -1) { RIP6STAT_INC(rip6s_isum); if (in6_cksum(m, proto, *offp, m->m_pkthdr.len - *offp)) { - INP_RUNLOCK(in6p); RIP6STAT_INC(rip6s_badsum); - continue; + goto skip_2; } } /* @@ -251,46 +288,13 @@ rip6_input(struct mbuf **mp, int *offp, int proto) } if (blocked != MCAST_PASS) { IP6STAT_INC(ip6s_notmember); - INP_RUNLOCK(in6p); - continue; + goto skip_2; } } - if (last != NULL) { - struct mbuf *n = m_copym(m, 0, M_COPYALL, M_NOWAIT); - -#if defined(IPSEC) || defined(IPSEC_SUPPORT) - /* - * Check AH/ESP integrity. - */ - if (IPSEC_ENABLED(ipv6)) { - if (n != NULL && - IPSEC_CHECK_POLICY(ipv6, n, last) != 0) { - m_freem(n); - /* Do not inject data into pcb. */ - n = NULL; - } - } -#endif /* IPSEC */ - if (n) { - if (last->inp_flags & INP_CONTROLOPTS || - last->inp_socket->so_options & SO_TIMESTAMP) - ip6_savecontrol(last, n, &opts); - /* strip intermediate headers */ - m_adj(n, *offp); - if (sbappendaddr(&last->inp_socket->so_rcv, - (struct sockaddr *)&fromsa, - n, opts) == 0) { - m_freem(n); - if (opts) - m_freem(opts); - RIP6STAT_INC(rip6s_fullsock); - } else - sorwakeup(last->inp_socket); - opts = NULL; - } - INP_RUNLOCK(last); - } last = in6p; + continue; +skip_2: + INP_RUNLOCK(in6p); } INP_INFO_RUNLOCK_ET(&V_ripcbinfo, et); #if defined(IPSEC) || defined(IPSEC_SUPPORT)