svn commit: r356619 - in stable/12: sys/netinet sys/netinet6 sys/netipsec tests/sys/netinet6

Bjoern A. Zeeb bz at FreeBSD.org
Fri Jan 10 23:46:14 UTC 2020


Author: bz
Date: Fri Jan 10 23:46:12 2020
New Revision: 356619
URL: https://svnweb.freebsd.org/changeset/base/356619

Log:
  MFC r354462,354643,354680,354731,354748-354750,354757,354831-354832,
      354861-354863,354865,355254,355450,355452
  
    netinet*: variable cleanup
    netinet*: update *mp to pass the proper value back
    nd6 defrouter: consolidate nd_defrouter manipulations in nd6_rtr.c
      (excluding some changes to keep public KPI)
    nd6: simplify code
    netinet6: Remove PULLDOWN_TESTs.
    netinet*: replace IP6_EXTHDR_GET()
    IP6_EXTHDR_CHECK(): remove the last instances
    nd6_rtr: consollidation and more consistent naming
    ipv6 tests: Add a simple ping6 test as well.
    icmpv6: Fix mbuf change in mld
    nd6_rtr: re-sort functions
    nd6: make nd6_timer_ch static
    nd6: sysctl
    in6: move include
    Fix m_pullup() problem after removing PULLDOWN_TESTs and KAME EXT* macros.
      (IP6_EXTHDR* macros are preserved in stable).
    ip6_input: remove redundant v4mapped check
    Update comment.
  
  PR:		240135

Added:
  stable/12/tests/sys/netinet6/mld.py
     - copied unchanged from r354832, head/tests/sys/netinet6/mld.py
  stable/12/tests/sys/netinet6/mld.sh
     - copied unchanged from r354832, head/tests/sys/netinet6/mld.sh
Modified:
  stable/12/sys/netinet/ip_carp.c
  stable/12/sys/netinet/tcp_input.c
  stable/12/sys/netinet/udp_usrreq.c
  stable/12/sys/netinet6/dest6.c
  stable/12/sys/netinet6/frag6.c
  stable/12/sys/netinet6/icmp6.c
  stable/12/sys/netinet6/in6.c
  stable/12/sys/netinet6/ip6_input.c
  stable/12/sys/netinet6/ip6_mroute.c
  stable/12/sys/netinet6/mld6.c
  stable/12/sys/netinet6/mld6_var.h
  stable/12/sys/netinet6/nd6.c
  stable/12/sys/netinet6/nd6.h
  stable/12/sys/netinet6/nd6_nbr.c
  stable/12/sys/netinet6/nd6_rtr.c
  stable/12/sys/netinet6/route6.c
  stable/12/sys/netinet6/sctp6_usrreq.c
  stable/12/sys/netinet6/udp6_usrreq.c
  stable/12/sys/netipsec/xform_ah.c
  stable/12/sys/netipsec/xform_esp.c
  stable/12/tests/sys/netinet6/Makefile
  stable/12/tests/sys/netinet6/exthdr.sh
Directory Properties:
  stable/12/   (props changed)

Modified: stable/12/sys/netinet/ip_carp.c
==============================================================================
--- stable/12/sys/netinet/ip_carp.c	Fri Jan 10 22:49:14 2020	(r356618)
+++ stable/12/sys/netinet/ip_carp.c	Fri Jan 10 23:46:12 2020	(r356619)
@@ -566,13 +566,16 @@ carp6_input(struct mbuf **mp, int *offp, int proto)
 	}
 
 	/* verify that we have a complete carp packet */
-	len = m->m_len;
-	IP6_EXTHDR_GET(ch, struct carp_header *, m, *offp, sizeof(*ch));
-	if (ch == NULL) {
-		CARPSTATS_INC(carps_badlen);
-		CARP_DEBUG("%s: packet size %u too small\n", __func__, len);
-		return (IPPROTO_DONE);
+	if (m->m_len < *offp + sizeof(*ch)) {
+		len = m->m_len;
+		m = m_pullup(m, *offp + sizeof(*ch));
+		if (m == NULL) {
+			CARPSTATS_INC(carps_badlen);
+			CARP_DEBUG("%s: packet size %u too small\n", __func__, len);
+			return (IPPROTO_DONE);
+		}
 	}
+	ch = (struct carp_header *)(mtod(m, caddr_t) + *offp);
 
 
 	/* verify the CARP checksum */

Modified: stable/12/sys/netinet/tcp_input.c
==============================================================================
--- stable/12/sys/netinet/tcp_input.c	Fri Jan 10 22:49:14 2020	(r356618)
+++ stable/12/sys/netinet/tcp_input.c	Fri Jan 10 23:46:12 2020	(r356619)
@@ -534,11 +534,19 @@ cc_ecnpkt_handler(struct tcpcb *tp, struct tcphdr *th,
 int
 tcp6_input(struct mbuf **mp, int *offp, int proto)
 {
-	struct mbuf *m = *mp;
+	struct mbuf *m;
 	struct in6_ifaddr *ia6;
 	struct ip6_hdr *ip6;
 
-	IP6_EXTHDR_CHECK(m, *offp, sizeof(struct tcphdr), IPPROTO_DONE);
+	m = *mp;
+	if (m->m_len < *offp + sizeof(struct tcphdr)) {
+		m = m_pullup(m, *offp + sizeof(struct tcphdr));
+		if (m == NULL) {
+			*mp = m;
+			TCPSTAT_INC(tcps_rcvshort);
+			return (IPPROTO_DONE);
+		}
+	}
 
 	/*
 	 * draft-itojun-ipv6-tcp-to-anycast
@@ -547,17 +555,17 @@ tcp6_input(struct mbuf **mp, int *offp, int proto)
 	ip6 = mtod(m, struct ip6_hdr *);
 	ia6 = in6ifa_ifwithaddr(&ip6->ip6_dst, 0 /* XXX */);
 	if (ia6 && (ia6->ia6_flags & IN6_IFF_ANYCAST)) {
-		struct ip6_hdr *ip6;
 
 		ifa_free(&ia6->ia_ifa);
-		ip6 = mtod(m, struct ip6_hdr *);
 		icmp6_error(m, ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_ADDR,
 			    (caddr_t)&ip6->ip6_dst - (caddr_t)ip6);
+		*mp = NULL;
 		return (IPPROTO_DONE);
 	}
 	if (ia6)
 		ifa_free(&ia6->ia_ifa);
 
+	*mp = m;
 	return (tcp_input(mp, offp, proto));
 }
 #endif /* INET6 */
@@ -616,16 +624,7 @@ tcp_input(struct mbuf **mp, int *offp, int proto)
 
 #ifdef INET6
 	if (isipv6) {
-		/* IP6_EXTHDR_CHECK() is already done at tcp6_input(). */
 
-		if (m->m_len < (sizeof(*ip6) + sizeof(*th))) {
-			m = m_pullup(m, sizeof(*ip6) + sizeof(*th));
-			if (m == NULL) {
-				TCPSTAT_INC(tcps_rcvshort);
-				return (IPPROTO_DONE);
-			}
-		}
-
 		ip6 = mtod(m, struct ip6_hdr *);
 		th = (struct tcphdr *)((caddr_t)ip6 + off0);
 		tlen = sizeof(*ip6) + ntohs(ip6->ip6_plen) - off0;
@@ -733,7 +732,13 @@ tcp_input(struct mbuf **mp, int *offp, int proto)
 	if (off > sizeof (struct tcphdr)) {
 #ifdef INET6
 		if (isipv6) {
-			IP6_EXTHDR_CHECK(m, off0, off, IPPROTO_DONE);
+			if (m->m_len < off0 + off) {
+				m = m_pullup(m, off0 + off);
+				if (m == NULL) {
+					TCPSTAT_INC(tcps_rcvshort);
+					return (IPPROTO_DONE);
+				}
+			}
 			ip6 = mtod(m, struct ip6_hdr *);
 			th = (struct tcphdr *)((caddr_t)ip6 + off0);
 		}

Modified: stable/12/sys/netinet/udp_usrreq.c
==============================================================================
--- stable/12/sys/netinet/udp_usrreq.c	Fri Jan 10 22:49:14 2020	(r356618)
+++ stable/12/sys/netinet/udp_usrreq.c	Fri Jan 10 23:46:12 2020	(r356619)
@@ -421,14 +421,13 @@ udp_input(struct mbuf **mp, int *offp, int proto)
 	/*
 	 * Get IP and UDP header together in first mbuf.
 	 */
-	ip = mtod(m, struct ip *);
 	if (m->m_len < iphlen + sizeof(struct udphdr)) {
 		if ((m = m_pullup(m, iphlen + sizeof(struct udphdr))) == NULL) {
 			UDPSTAT_INC(udps_hdrops);
 			return (IPPROTO_DONE);
 		}
-		ip = mtod(m, struct ip *);
 	}
+	ip = mtod(m, struct ip *);
 	uh = (struct udphdr *)((caddr_t)ip + iphlen);
 	cscov_partial = (proto == IPPROTO_UDPLITE) ? 1 : 0;
 

Modified: stable/12/sys/netinet6/dest6.c
==============================================================================
--- stable/12/sys/netinet6/dest6.c	Fri Jan 10 22:49:14 2020	(r356618)
+++ stable/12/sys/netinet6/dest6.c	Fri Jan 10 23:46:12 2020	(r356619)
@@ -64,30 +64,35 @@ __FBSDID("$FreeBSD$");
 int
 dest6_input(struct mbuf **mp, int *offp, int proto)
 {
-	struct mbuf *m = *mp;
-	int off = *offp, dstoptlen, optlen;
+	struct mbuf *m;
+	int off, dstoptlen, optlen;
 	struct ip6_dest *dstopts;
 	u_int8_t *opt;
 
-	/* validation of the length of the header */
-#ifndef PULLDOWN_TEST
-	IP6_EXTHDR_CHECK(m, off, sizeof(*dstopts), IPPROTO_DONE);
+	m = *mp;
+	off = *offp;
+
+	/* Validation of the length of the header. */
+	if (m->m_len < off + sizeof(*dstopts)) {
+		m = m_pullup(m, off + sizeof(*dstopts));
+		if (m == NULL) {
+			IP6STAT_INC(ip6s_exthdrtoolong);
+			*mp = m;
+			return (IPPROTO_DONE);
+		}
+	}
 	dstopts = (struct ip6_dest *)(mtod(m, caddr_t) + off);
-#else
-	IP6_EXTHDR_GET(dstopts, struct ip6_dest *, m, off, sizeof(*dstopts));
-	if (dstopts == NULL)
-		return IPPROTO_DONE;
-#endif
 	dstoptlen = (dstopts->ip6d_len + 1) << 3;
 
-#ifndef PULLDOWN_TEST
-	IP6_EXTHDR_CHECK(m, off, dstoptlen, IPPROTO_DONE);
+	if (m->m_len < off + dstoptlen) {
+		m = m_pullup(m, off + dstoptlen);
+		if (m == NULL) {
+			IP6STAT_INC(ip6s_exthdrtoolong);
+			*mp = m;
+			return (IPPROTO_DONE);
+		}
+	}
 	dstopts = (struct ip6_dest *)(mtod(m, caddr_t) + off);
-#else
-	IP6_EXTHDR_GET(dstopts, struct ip6_dest *, m, off, dstoptlen);
-	if (dstopts == NULL)
-		return IPPROTO_DONE;
-#endif
 	off += dstoptlen;
 	dstoptlen -= sizeof(struct ip6_dest);
 	opt = (u_int8_t *)dstopts + sizeof(struct ip6_dest);
@@ -110,17 +115,21 @@ dest6_input(struct mbuf **mp, int *offp, int proto)
 		default:		/* unknown option */
 			optlen = ip6_unknown_opt(opt, m,
 			    opt - mtod(m, u_int8_t *));
-			if (optlen == -1)
+			if (optlen == -1) {
+				*mp = NULL;
 				return (IPPROTO_DONE);
+			}
 			optlen += 2;
 			break;
 		}
 	}
 
 	*offp = off;
+	*mp = m;
 	return (dstopts->ip6d_nxt);
 
   bad:
 	m_freem(m);
+	*mp = NULL;
 	return (IPPROTO_DONE);
 }

Modified: stable/12/sys/netinet6/frag6.c
==============================================================================
--- stable/12/sys/netinet6/frag6.c	Fri Jan 10 22:49:14 2020	(r356618)
+++ stable/12/sys/netinet6/frag6.c	Fri Jan 10 23:46:12 2020	(r356619)
@@ -218,30 +218,22 @@ SYSCTL_INT(_net_inet6_ip6, IPV6CTL_MAXFRAGBUCKETSIZE, 
  * Remove the IPv6 fragmentation header from the mbuf.
  */
 int
-ip6_deletefraghdr(struct mbuf *m, int offset, int wait)
+ip6_deletefraghdr(struct mbuf *m, int offset, int wait __unused)
 {
 	struct ip6_hdr *ip6;
-	struct mbuf *t;
 
-	/* Delete frag6 header. */
-	if (m->m_len >= offset + sizeof(struct ip6_frag)) {
+	KASSERT(m->m_len >= offset + sizeof(struct ip6_frag),
+	    ("%s: ext headers not contigous in mbuf %p m_len %d >= "
+	    "offset %d + %zu\n", __func__, m, m->m_len, offset,
+	    sizeof(struct ip6_frag)));
 
-		/* This is the only possible case with !PULLDOWN_TEST. */
-		ip6 = mtod(m, struct ip6_hdr *);
-		bcopy(ip6, (char *)ip6 + sizeof(struct ip6_frag),
-		    offset);
-		m->m_data += sizeof(struct ip6_frag);
-		m->m_len -= sizeof(struct ip6_frag);
-	} else {
-
-		/* This comes with no copy if the boundary is on cluster. */
-		if ((t = m_split(m, offset, wait)) == NULL)
-			return (ENOMEM);
-		m_adj(t, sizeof(struct ip6_frag));
-		m_cat(m, t);
-	}
-
+	/* Delete frag6 header. */
+	ip6 = mtod(m, struct ip6_hdr *);
+	bcopy(ip6, (char *)ip6 + sizeof(struct ip6_frag), offset);
+	m->m_data += sizeof(struct ip6_frag);
+	m->m_len -= sizeof(struct ip6_frag);
 	m->m_flags |= M_FRAGMENTED;
+
 	return (0);
 }
 
@@ -397,15 +389,15 @@ frag6_input(struct mbuf **mp, int *offp, int proto)
 
 	M_ASSERTPKTHDR(m);
 
+	if (m->m_len < offset + sizeof(struct ip6_frag)) {
+		m = m_pullup(m, offset + sizeof(struct ip6_frag));
+		if (m == NULL) {
+			IP6STAT_INC(ip6s_exthdrtoolong);
+			*mp = NULL;
+			return (IPPROTO_DONE);
+		}
+	}
 	ip6 = mtod(m, struct ip6_hdr *);
-#ifndef PULLDOWN_TEST
-	IP6_EXTHDR_CHECK(m, offset, sizeof(struct ip6_frag), IPPROTO_DONE);
-	ip6f = (struct ip6_frag *)((caddr_t)ip6 + offset);
-#else
-	IP6_EXTHDR_GET(ip6f, struct ip6_frag *, m, offset, sizeof(*ip6f));
-	if (ip6f == NULL)
-		return (IPPROTO_DONE);
-#endif
 
 	dstifp = NULL;
 	/* Find the destination interface of the packet. */
@@ -419,6 +411,7 @@ frag6_input(struct mbuf **mp, int *offp, int proto)
 	if (ip6->ip6_plen == 0) {
 		icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_HEADER, offset);
 		in6_ifstat_inc(dstifp, ifs6_reass_fail);
+		*mp = NULL;
 		return (IPPROTO_DONE);
 	}
 
@@ -428,11 +421,13 @@ frag6_input(struct mbuf **mp, int *offp, int proto)
 	 * sizeof(struct ip6_frag) == 8
 	 * sizeof(struct ip6_hdr) = 40
 	 */
+	ip6f = (struct ip6_frag *)((caddr_t)ip6 + offset);
 	if ((ip6f->ip6f_offlg & IP6F_MORE_FRAG) &&
 	    (((ntohs(ip6->ip6_plen) - offset) & 0x7) != 0)) {
 		icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_HEADER,
 		    offsetof(struct ip6_hdr, ip6_plen));
 		in6_ifstat_inc(dstifp, ifs6_reass_fail);
+		*mp = NULL;
 		return (IPPROTO_DONE);
 	}
 
@@ -477,6 +472,7 @@ frag6_input(struct mbuf **mp, int *offp, int proto)
 		    offsetof(struct ip6_hdr, ip6_plen));
 		in6_ifstat_inc(dstifp, ifs6_reass_fail);
 		IP6STAT_INC(ip6s_fragdropped);
+		*mp = NULL;
 		return (IPPROTO_DONE);
 	}
 
@@ -612,6 +608,7 @@ frag6_input(struct mbuf **mp, int *offp, int proto)
 			icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_HEADER,
 			    offset - sizeof(struct ip6_frag) +
 			    offsetof(struct ip6_frag, ip6f_offlg));
+			*mp = NULL;
 			return (IPPROTO_DONE);
 		}
 	} else if (fragoff + frgpartlen > IPV6_MAXPACKET) {
@@ -628,6 +625,7 @@ frag6_input(struct mbuf **mp, int *offp, int proto)
 		icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_HEADER,
 		    offset - sizeof(struct ip6_frag) +
 		    offsetof(struct ip6_frag, ip6f_offlg));
+		*mp = NULL;
 		return (IPPROTO_DONE);
 	}
 
@@ -778,6 +776,7 @@ postinsert:
 				frag6_freef(q6, bucket);
 			}
 			IP6QB_UNLOCK(bucket);
+			*mp = NULL;
 			return (IPPROTO_DONE);
 		}
 		plen += af6->ip6af_frglen;
@@ -789,6 +788,7 @@ postinsert:
 			frag6_freef(q6, bucket);
 		}
 		IP6QB_UNLOCK(bucket);
+		*mp = NULL;
 		return (IPPROTO_DONE);
 	}
 
@@ -827,16 +827,8 @@ postinsert:
 	V_ip6qb[bucket].count--;
 	atomic_subtract_int(&frag6_nfrags, q6->ip6q_nfrag);
 
-	if (ip6_deletefraghdr(m, offset, M_NOWAIT) != 0) {
-#ifdef MAC
-		mac_ip6q_destroy(q6);
-#endif
-		free(q6, M_FRAG6);
-		atomic_subtract_int(&V_frag6_nfragpackets, 1);
+	ip6_deletefraghdr(m, offset, M_NOWAIT);
 
-		goto dropfrag;
-	}
-
 	/* Set nxt(-hdr field value) to the original value. */
 	m_copyback(m, ip6_get_prevhdr(m, offset), sizeof(uint8_t),
 	    (caddr_t)&nxt);
@@ -878,6 +870,7 @@ postinsert:
 #ifdef RSS
 	/* Queue/dispatch for reprocessing. */
 	netisr_dispatch(NETISR_IPV6_DIRECT, m);
+	*mp = NULL;
 	return (IPPROTO_DONE);
 #endif
 
@@ -893,6 +886,7 @@ dropfrag2:
 	in6_ifstat_inc(dstifp, ifs6_reass_fail);
 	IP6STAT_INC(ip6s_fragdropped);
 	m_freem(m);
+	*mp = NULL;
 	return (IPPROTO_DONE);
 }
 

Modified: stable/12/sys/netinet6/icmp6.c
==============================================================================
--- stable/12/sys/netinet6/icmp6.c	Fri Jan 10 22:49:14 2020	(r356618)
+++ stable/12/sys/netinet6/icmp6.c	Fri Jan 10 23:46:12 2020	(r356619)
@@ -232,16 +232,13 @@ icmp6_error2(struct mbuf *m, int type, int code, int p
 	if (ifp == NULL)
 		return;
 
-#ifndef PULLDOWN_TEST
-	IP6_EXTHDR_CHECK(m, 0, sizeof(struct ip6_hdr), );
-#else
 	if (m->m_len < sizeof(struct ip6_hdr)) {
 		m = m_pullup(m, sizeof(struct ip6_hdr));
-		if (m == NULL)
+		if (m == NULL) {
+			IP6STAT_INC(ip6s_exthdrtoolong);
 			return;
+		}
 	}
-#endif
-
 	ip6 = mtod(m, struct ip6_hdr *);
 
 	if (in6_setscope(&ip6->ip6_src, ifp, NULL) != 0)
@@ -276,15 +273,13 @@ icmp6_error(struct mbuf *m, int type, int code, int pa
 	}
 #endif
 
-#ifndef PULLDOWN_TEST
-	IP6_EXTHDR_CHECK(m, 0, sizeof(struct ip6_hdr), );
-#else
 	if (m->m_len < sizeof(struct ip6_hdr)) {
 		m = m_pullup(m, sizeof(struct ip6_hdr));
-		if (m == NULL)
+		if (m == NULL) {
+			IP6STAT_INC(ip6s_exthdrtoolong);
 			return;
+		}
 	}
-#endif
 	oip6 = mtod(m, struct ip6_hdr *);
 
 	/*
@@ -322,17 +317,16 @@ icmp6_error(struct mbuf *m, int type, int code, int pa
 	if (off >= 0 && nxt == IPPROTO_ICMPV6) {
 		struct icmp6_hdr *icp;
 
-#ifndef PULLDOWN_TEST
-		IP6_EXTHDR_CHECK(m, 0, off + sizeof(struct icmp6_hdr), );
-		icp = (struct icmp6_hdr *)(mtod(m, caddr_t) + off);
-#else
-		IP6_EXTHDR_GET(icp, struct icmp6_hdr *, m, off,
-			sizeof(*icp));
-		if (icp == NULL) {
-			ICMP6STAT_INC(icp6s_tooshort);
-			return;
+		if (m->m_len < off + sizeof(struct icmp6_hdr)) {
+			m = m_pullup(m, off + sizeof(struct icmp6_hdr));
+			if (m == NULL) {
+				IP6STAT_INC(ip6s_exthdrtoolong);
+				return;
+			}
 		}
-#endif
+		oip6 = mtod(m, struct ip6_hdr *);
+		icp = (struct icmp6_hdr *)(mtod(m, caddr_t) + off);
+
 		if (icp->icmp6_type < ICMP6_ECHO_REQUEST ||
 		    icp->icmp6_type == ND_REDIRECT) {
 			/*
@@ -349,8 +343,6 @@ icmp6_error(struct mbuf *m, int type, int code, int pa
 		/* non-ICMPv6 - send the error */
 	}
 
-	oip6 = mtod(m, struct ip6_hdr *); /* adjust pointer */
-
 	/* Finally, do rate limitation check. */
 	if (icmp6_ratelimit(&oip6->ip6_src, type, code)) {
 		ICMP6STAT_INC(icp6s_toofreq);
@@ -401,35 +393,38 @@ icmp6_error(struct mbuf *m, int type, int code, int pa
 int
 icmp6_input(struct mbuf **mp, int *offp, int proto)
 {
-	struct mbuf *m = *mp, *n;
+	struct mbuf *m, *n;
 	struct ifnet *ifp;
 	struct ip6_hdr *ip6, *nip6;
 	struct icmp6_hdr *icmp6, *nicmp6;
-	int off = *offp;
-	int icmp6len = m->m_pkthdr.len - *offp;
-	int code, sum, noff;
 	char ip6bufs[INET6_ADDRSTRLEN], ip6bufd[INET6_ADDRSTRLEN];
-	int ip6len, error;
+	int code, error, icmp6len, ip6len, noff, off, sum;
 
-	ifp = m->m_pkthdr.rcvif;
+	m = *mp;
+	off = *offp;
 
-#ifndef PULLDOWN_TEST
-	IP6_EXTHDR_CHECK(m, off, sizeof(struct icmp6_hdr), IPPROTO_DONE);
-	/* m might change if M_LOOP.  So, call mtod after this */
-#endif
+	if (m->m_len < off + sizeof(struct icmp6_hdr)) {
+		m = m_pullup(m, off + sizeof(struct icmp6_hdr));
+		if (m == NULL) {
+			IP6STAT_INC(ip6s_exthdrtoolong);
+			*mp = m;
+			return (IPPROTO_DONE);
+		}
+	}
 
 	/*
 	 * Locate icmp6 structure in mbuf, and check
 	 * that not corrupted and of at least minimum length
 	 */
 
-	ip6 = mtod(m, struct ip6_hdr *);
-	ip6len = sizeof(struct ip6_hdr) + ntohs(ip6->ip6_plen);
+	icmp6len = m->m_pkthdr.len - off;
 	if (icmp6len < sizeof(struct icmp6_hdr)) {
 		ICMP6STAT_INC(icp6s_tooshort);
 		goto freeit;
 	}
 
+	ip6 = mtod(m, struct ip6_hdr *);
+	ifp = m->m_pkthdr.rcvif;
 	/*
 	 * Check multicast group membership.
 	 * Note: SSM filters are not applied for ICMPv6 traffic.
@@ -445,20 +440,9 @@ icmp6_input(struct mbuf **mp, int *offp, int proto)
 		}
 	}
 
-	/*
-	 * calculate the checksum
-	 */
-#ifndef PULLDOWN_TEST
+	/* Calculate the checksum. */
 	icmp6 = (struct icmp6_hdr *)((caddr_t)ip6 + off);
-#else
-	IP6_EXTHDR_GET(icmp6, struct icmp6_hdr *, m, off, sizeof(*icmp6));
-	if (icmp6 == NULL) {
-		ICMP6STAT_INC(icp6s_tooshort);
-		return IPPROTO_DONE;
-	}
-#endif
 	code = icmp6->icmp6_code;
-
 	if ((sum = in6_cksum(m, IPPROTO_ICMPV6, off, icmp6len)) != 0) {
 		nd6log((LOG_ERR,
 		    "ICMP6 checksum error(%d|%x) %s\n",
@@ -473,6 +457,7 @@ icmp6_input(struct mbuf **mp, int *offp, int proto)
 	if (icmp6->icmp6_type < ICMP6_INFOMSG_MASK)
 		icmp6_ifstat_inc(ifp, ifs6_in_error);
 
+	ip6len = sizeof(struct ip6_hdr) + ntohs(ip6->ip6_plen);
 	switch (icmp6->icmp6_type) {
 	case ICMP6_DST_UNREACH:
 		icmp6_ifstat_inc(ifp, ifs6_in_dstunreach);
@@ -585,8 +570,14 @@ icmp6_input(struct mbuf **mp, int *offp, int proto)
 			n->m_pkthdr.len = n0len + (noff - off);
 			n->m_next = n0;
 		} else {
-			IP6_EXTHDR_GET(nicmp6, struct icmp6_hdr *, n, off,
-			    sizeof(*nicmp6));
+			if (n->m_len < off + sizeof(*nicmp6)) {
+				n = m_pullup(n, off + sizeof(*nicmp6));
+				if (n == NULL) {
+					IP6STAT_INC(ip6s_exthdrtoolong);
+					break;
+				}
+			}
+			nicmp6 = (struct icmp6_hdr *)(mtod(n, caddr_t) + off);
 			noff = off;
 		}
 		if (n) {
@@ -619,8 +610,10 @@ icmp6_input(struct mbuf **mp, int *offp, int proto)
 		 */
 		if ((ip6->ip6_hlim != 1) || (m->m_flags & M_RTALERT_MLD) == 0)
 			goto freeit;
-		if (mld_input(m, off, icmp6len) != 0)
+		if (mld_input(&m, off, icmp6len) != 0) {
+			*mp = NULL;
 			return (IPPROTO_DONE);
+		}
 		/* m stays. */
 		break;
 
@@ -639,10 +632,15 @@ icmp6_input(struct mbuf **mp, int *offp, int proto)
 			goto badlen;
 
 		if (mode == FQDN) {
-#ifndef PULLDOWN_TEST
-			IP6_EXTHDR_CHECK(m, off, sizeof(struct icmp6_nodeinfo),
-			    IPPROTO_DONE);
-#endif
+			if (m->m_len < off + sizeof(struct icmp6_nodeinfo)) {
+				m = m_pullup(m, off +
+				    sizeof(struct icmp6_nodeinfo));
+				if (m == NULL) {
+					IP6STAT_INC(ip6s_exthdrtoolong);
+					*mp = m;
+					return (IPPROTO_DONE);
+				}
+			}
 			n = m_copym(m, 0, M_COPYALL, M_NOWAIT);
 			if (n)
 				n = ni6_input(n, off);
@@ -728,7 +726,14 @@ icmp6_input(struct mbuf **mp, int *offp, int proto)
 		if (icmp6len < sizeof(struct nd_router_solicit))
 			goto badlen;
 		if (send_sendso_input_hook != NULL) {
-			IP6_EXTHDR_CHECK(m, off, icmp6len, IPPROTO_DONE);
+			if (m->m_len < off + icmp6len) {
+				m = m_pullup(m, off + icmp6len);
+				if (m == NULL) {
+					IP6STAT_INC(ip6s_exthdrtoolong);
+					*mp = NULL;
+					return (IPPROTO_DONE);
+				}
+			}
 			error = send_sendso_input_hook(m, ifp, SND_IN, ip6len);
 			if (error == 0) {
 				m = NULL;
@@ -847,6 +852,7 @@ icmp6_input(struct mbuf **mp, int *offp, int proto)
 	deliver:
 		if (icmp6_notify_error(&m, off, icmp6len, code) != 0) {
 			/* In this case, m should've been freed. */
+			*mp = NULL;
 			return (IPPROTO_DONE);
 		}
 		break;
@@ -863,38 +869,40 @@ icmp6_input(struct mbuf **mp, int *offp, int proto)
 	/* deliver the packet to appropriate sockets */
 	icmp6_rip6_input(&m, *offp);
 
-	return IPPROTO_DONE;
+	*mp = m;
+	return (IPPROTO_DONE);
 
  freeit:
 	m_freem(m);
-	return IPPROTO_DONE;
+	*mp = NULL;
+	return (IPPROTO_DONE);
 }
 
 static int
 icmp6_notify_error(struct mbuf **mp, int off, int icmp6len, int code)
 {
-	struct mbuf *m = *mp;
+	struct mbuf *m;
 	struct icmp6_hdr *icmp6;
 	struct ip6_hdr *eip6;
 	u_int32_t notifymtu;
 	struct sockaddr_in6 icmp6src, icmp6dst;
 
+	m = *mp;
+
 	if (icmp6len < sizeof(struct icmp6_hdr) + sizeof(struct ip6_hdr)) {
 		ICMP6STAT_INC(icp6s_tooshort);
 		goto freeit;
 	}
-#ifndef PULLDOWN_TEST
-	IP6_EXTHDR_CHECK(m, off,
-	    sizeof(struct icmp6_hdr) + sizeof(struct ip6_hdr), -1);
-	icmp6 = (struct icmp6_hdr *)(mtod(m, caddr_t) + off);
-#else
-	IP6_EXTHDR_GET(icmp6, struct icmp6_hdr *, m, off,
-	    sizeof(*icmp6) + sizeof(struct ip6_hdr));
-	if (icmp6 == NULL) {
-		ICMP6STAT_INC(icp6s_tooshort);
-		return (-1);
+
+	if (m->m_len < off + sizeof(*icmp6) + sizeof(struct ip6_hdr)) {
+		m = m_pullup(m, off + sizeof(*icmp6) + sizeof(struct ip6_hdr));
+		if (m == NULL) {
+			IP6STAT_INC(ip6s_exthdrtoolong);
+			*mp = m;
+			return (-1);
+		}
 	}
-#endif
+	icmp6 = (struct icmp6_hdr *)(mtod(m, caddr_t) + off);
 	eip6 = (struct ip6_hdr *)(icmp6 + 1);
 
 	/* Detect the upper level protocol */
@@ -918,19 +926,17 @@ icmp6_notify_error(struct mbuf **mp, int off, int icmp
 			case IPPROTO_HOPOPTS:
 			case IPPROTO_DSTOPTS:
 			case IPPROTO_AH:
-#ifndef PULLDOWN_TEST
-				IP6_EXTHDR_CHECK(m, 0,
-				    eoff + sizeof(struct ip6_ext), -1);
-				eh = (struct ip6_ext *)(mtod(m, caddr_t) + eoff);
-#else
-				IP6_EXTHDR_GET(eh, struct ip6_ext *, m,
-				    eoff, sizeof(*eh));
-				if (eh == NULL) {
-					ICMP6STAT_INC(icp6s_tooshort);
-					return (-1);
+				if (m->m_len < eoff + sizeof(struct ip6_ext)) {
+					m = m_pullup(m, eoff +
+					    sizeof(struct ip6_ext));
+					if (m == NULL) {
+						IP6STAT_INC(ip6s_exthdrtoolong);
+						*mp = m;
+						return (-1);
+					}
 				}
-#endif
-
+				eh = (struct ip6_ext *)
+				    (mtod(m, caddr_t) + eoff);
 				if (nxt == IPPROTO_AH)
 					eoff += (eh->ip6e_len + 2) << 2;
 				else
@@ -946,18 +952,16 @@ icmp6_notify_error(struct mbuf **mp, int off, int icmp
 				 * information that depends on the final
 				 * destination (e.g. path MTU).
 				 */
-#ifndef PULLDOWN_TEST
-				IP6_EXTHDR_CHECK(m, 0, eoff + sizeof(*rth), -1);
+				if (m->m_len < eoff + sizeof(*rth)) {
+					m = m_pullup(m, eoff + sizeof(*rth));
+					if (m == NULL) {
+						IP6STAT_INC(ip6s_exthdrtoolong);
+						*mp = m;
+						return (-1);
+					}
+				}
 				rth = (struct ip6_rthdr *)
 				    (mtod(m, caddr_t) + eoff);
-#else
-				IP6_EXTHDR_GET(rth, struct ip6_rthdr *, m,
-				    eoff, sizeof(*rth));
-				if (rth == NULL) {
-					ICMP6STAT_INC(icp6s_tooshort);
-					return (-1);
-				}
-#endif
 				rthlen = (rth->ip6r_len + 1) << 3;
 				/*
 				 * XXX: currently there is no
@@ -971,19 +975,17 @@ icmp6_notify_error(struct mbuf **mp, int off, int icmp
 				    rth->ip6r_type == IPV6_RTHDR_TYPE_0) {
 					int hops;
 
-#ifndef PULLDOWN_TEST
-					IP6_EXTHDR_CHECK(m, 0, eoff + rthlen, -1);
+					if (m->m_len < eoff + rthlen) {
+						m = m_pullup(m, eoff + rthlen);
+						if (m == NULL) {
+							IP6STAT_INC(
+							    ip6s_exthdrtoolong);
+							*mp = m;
+							return (-1);
+						}
+					}
 					rth0 = (struct ip6_rthdr0 *)
 					    (mtod(m, caddr_t) + eoff);
-#else
-					IP6_EXTHDR_GET(rth0,
-					    struct ip6_rthdr0 *, m,
-					    eoff, rthlen);
-					if (rth0 == NULL) {
-						ICMP6STAT_INC(icp6s_tooshort);
-						return (-1);
-					}
-#endif
 					/* just ignore a bogus header */
 					if ((rth0->ip6r0_len % 2) == 0 &&
 					    (hops = rth0->ip6r0_len/2))
@@ -993,19 +995,17 @@ icmp6_notify_error(struct mbuf **mp, int off, int icmp
 				nxt = rth->ip6r_nxt;
 				break;
 			case IPPROTO_FRAGMENT:
-#ifndef PULLDOWN_TEST
-				IP6_EXTHDR_CHECK(m, 0, eoff +
-				    sizeof(struct ip6_frag), -1);
+				if (m->m_len < eoff + sizeof(struct ip6_frag)) {
+					m = m_pullup(m, eoff +
+					    sizeof(struct ip6_frag));
+					if (m == NULL) {
+						IP6STAT_INC(ip6s_exthdrtoolong);
+						*mp = m;
+						return (-1);
+					}
+				}
 				fh = (struct ip6_frag *)(mtod(m, caddr_t) +
 				    eoff);
-#else
-				IP6_EXTHDR_GET(fh, struct ip6_frag *, m,
-				    eoff, sizeof(*fh));
-				if (fh == NULL) {
-					ICMP6STAT_INC(icp6s_tooshort);
-					return (-1);
-				}
-#endif
 				/*
 				 * Data after a fragment header is meaningless
 				 * unless it is the first fragment, but
@@ -1031,16 +1031,7 @@ icmp6_notify_error(struct mbuf **mp, int off, int icmp
 			}
 		}
 	  notify:
-#ifndef PULLDOWN_TEST
 		icmp6 = (struct icmp6_hdr *)(mtod(m, caddr_t) + off);
-#else
-		IP6_EXTHDR_GET(icmp6, struct icmp6_hdr *, m, off,
-		    sizeof(*icmp6) + sizeof(struct ip6_hdr));
-		if (icmp6 == NULL) {
-			ICMP6STAT_INC(icp6s_tooshort);
-			return (-1);
-		}
-#endif
 
 		/*
 		 * retrieve parameters from the inner IPv6 header, and convert
@@ -1098,6 +1089,7 @@ icmp6_notify_error(struct mbuf **mp, int off, int icmp
 
   freeit:
 	m_freem(m);
+	*mp = NULL;
 	return (-1);
 }
 
@@ -1185,15 +1177,7 @@ ni6_input(struct mbuf *m, int off)
 	struct in6_ifaddr *ia6 = NULL;
 
 	ip6 = mtod(m, struct ip6_hdr *);
-#ifndef PULLDOWN_TEST
 	ni6 = (struct icmp6_nodeinfo *)(mtod(m, caddr_t) + off);
-#else
-	IP6_EXTHDR_GET(ni6, struct icmp6_nodeinfo *, m, off, sizeof(*ni6));
-	if (ni6 == NULL) {
-		/* m is already reclaimed */
-		return (NULL);
-	}
-#endif
 
 	/*
 	 * Validate IPv6 source address.
@@ -1290,7 +1274,6 @@ ni6_input(struct mbuf *m, int off)
 			 *
 			 * We do not do proxy at this moment.
 			 */
-			/* m_pulldown instead of copy? */
 			m_copydata(m, off + sizeof(struct icmp6_nodeinfo),
 			    subjlen, (caddr_t)&in6_subj);
 			if (in6_setscope(&in6_subj, m->m_pkthdr.rcvif, NULL))
@@ -1330,10 +1313,19 @@ ni6_input(struct mbuf *m, int off)
 			mtx_unlock(&pr->pr_mtx);
 			if (!n || n->m_next || n->m_len == 0)
 				goto bad;
-			IP6_EXTHDR_GET(subj, char *, m,
-			    off + sizeof(struct icmp6_nodeinfo), subjlen);
-			if (subj == NULL)
-				goto bad;
+			if (m->m_len < off + sizeof(struct icmp6_nodeinfo) +
+			    subjlen) {
+				m = m_pullup(m, off +
+				    sizeof(struct icmp6_nodeinfo) + subjlen);
+				if (m == NULL) {
+					IP6STAT_INC(ip6s_exthdrtoolong);
+					goto bad;
+				}
+			}
+			/* ip6 possibly invalid but not used after. */
+			ni6 = (struct icmp6_nodeinfo *)(mtod(m, caddr_t) + off);
+			subj = (char *)(mtod(m, caddr_t) + off +
+			    sizeof(struct icmp6_nodeinfo));
 			if (!ni6_dnsmatch(subj, subjlen, mtod(n, const char *),
 			    n->m_len)) {
 				goto bad;
@@ -1899,16 +1891,8 @@ icmp6_rip6_input(struct mbuf **mp, int off)
 	struct epoch_tracker et;
 	struct mbuf *opts = NULL;
 
-#ifndef PULLDOWN_TEST
-	/* this is assumed to be safe. */
+	/* This is assumed to be safe; icmp6_input() does a pullup. */
 	icmp6 = (struct icmp6_hdr *)((caddr_t)ip6 + off);
-#else
-	IP6_EXTHDR_GET(icmp6, struct icmp6_hdr *, m, off, sizeof(*icmp6));
-	if (icmp6 == NULL) {
-		/* m is already reclaimed */
-		return (IPPROTO_DONE);
-	}
-#endif
 
 	/*
 	 * XXX: the address may have embedded scope zone ID, which should be
@@ -1920,6 +1904,7 @@ icmp6_rip6_input(struct mbuf **mp, int off)
 	fromsa.sin6_addr = ip6->ip6_src;
 	if (sa6_recoverscope(&fromsa)) {
 		m_freem(m);
+		*mp = NULL;
 		return (IPPROTO_DONE);
 	}
 
@@ -2045,7 +2030,8 @@ icmp6_rip6_input(struct mbuf **mp, int off)
 		m_freem(m);
 		IP6STAT_DEC(ip6s_delivered);
 	}
-	return IPPROTO_DONE;
+	*mp = NULL;
+	return (IPPROTO_DONE);
 }
 
 /*
@@ -2223,24 +2209,17 @@ void
 icmp6_redirect_input(struct mbuf *m, int off)
 {
 	struct ifnet *ifp;
-	struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
+	struct ip6_hdr *ip6;
 	struct nd_redirect *nd_rd;
-	int icmp6len = ntohs(ip6->ip6_plen);
-	char *lladdr = NULL;
-	int lladdrlen = 0;
-	int is_router;
-	int is_onlink;
-	struct in6_addr src6 = ip6->ip6_src;
-	struct in6_addr redtgt6;
-	struct in6_addr reddst6;
+	struct in6_addr src6, redtgt6, reddst6;
 	union nd_opts ndopts;
 	char ip6buf[INET6_ADDRSTRLEN];
+	char *lladdr;
+	int icmp6len, is_onlink, is_router, lladdrlen;
 
 	M_ASSERTPKTHDR(m);
 	KASSERT(m->m_pkthdr.rcvif != NULL, ("%s: no rcvif", __func__));
 
-	ifp = m->m_pkthdr.rcvif;
-
 	/* XXX if we are router, we don't update route by icmp6 redirect */
 	if (V_ip6_forwarding)
 		goto freeit;
@@ -2251,25 +2230,29 @@ icmp6_redirect_input(struct mbuf *m, int off)
 	if(m->m_flags & M_FRAGMENTED)
 		goto freeit;
 
-#ifndef PULLDOWN_TEST
-	IP6_EXTHDR_CHECK(m, off, icmp6len,);
-	nd_rd = (struct nd_redirect *)((caddr_t)ip6 + off);
-#else
-	IP6_EXTHDR_GET(nd_rd, struct nd_redirect *, m, off, icmp6len);
-	if (nd_rd == NULL) {
-		ICMP6STAT_INC(icp6s_tooshort);
-		return;
+	ip6 = mtod(m, struct ip6_hdr *);
+	icmp6len = ntohs(ip6->ip6_plen);
+	if (m->m_len < off + icmp6len) {
+		m = m_pullup(m, off + icmp6len);
+		if (m == NULL) {
+			IP6STAT_INC(ip6s_exthdrtoolong);
+			return;
+		}
 	}
-#endif
+	ip6 = mtod(m, struct ip6_hdr *);
+	nd_rd = (struct nd_redirect *)((caddr_t)ip6 + off);
+
+	ifp = m->m_pkthdr.rcvif;
 	redtgt6 = nd_rd->nd_rd_target;
 	reddst6 = nd_rd->nd_rd_dst;
 
-	if (in6_setscope(&redtgt6, m->m_pkthdr.rcvif, NULL) ||
-	    in6_setscope(&reddst6, m->m_pkthdr.rcvif, NULL)) {
+	if (in6_setscope(&redtgt6, ifp, NULL) ||
+	    in6_setscope(&reddst6, ifp, NULL)) {
 		goto freeit;
 	}
 
 	/* validation */
+	src6 = ip6->ip6_src;
 	if (!IN6_IS_ADDR_LINKLOCAL(&src6)) {
 		nd6log((LOG_ERR,
 		    "ICMP6 redirect sent from %s rejected; "
@@ -2355,6 +2338,8 @@ icmp6_redirect_input(struct mbuf *m, int off)
 		goto freeit;
 	}
 
+	lladdr = NULL;
+	lladdrlen = 0;
 	if (ndopts.nd_opts_tgt_lladdr) {
 		lladdr = (char *)(ndopts.nd_opts_tgt_lladdr + 1);
 		lladdrlen = ndopts.nd_opts_tgt_lladdr->nd_opt_len << 3;

Modified: stable/12/sys/netinet6/in6.c
==============================================================================
--- stable/12/sys/netinet6/in6.c	Fri Jan 10 22:49:14 2020	(r356618)
+++ stable/12/sys/netinet6/in6.c	Fri Jan 10 23:46:12 2020	(r356619)
@@ -84,6 +84,7 @@ __FBSDID("$FreeBSD$");
 #include <sys/kernel.h>
 #include <sys/lock.h>
 #include <sys/rmlock.h>
+#include <sys/sysctl.h>
 #include <sys/syslog.h>
 
 #include <net/if.h>
@@ -2022,8 +2023,6 @@ in6_if2idlen(struct ifnet *ifp)
 		return (64);
 	}
 }
-
-#include <sys/sysctl.h>
 
 struct in6_llentry {
 	struct llentry		base;

Modified: stable/12/sys/netinet6/ip6_input.c
==============================================================================
--- stable/12/sys/netinet6/ip6_input.c	Fri Jan 10 22:49:14 2020	(r356618)
+++ stable/12/sys/netinet6/ip6_input.c	Fri Jan 10 23:46:12 2020	(r356619)
@@ -203,9 +203,6 @@ struct rmlock in6_ifaddr_lock;
 RM_SYSINIT(in6_ifaddr_lock, &in6_ifaddr_lock, "in6_ifaddr_lock");
 
 static int ip6_hopopts_input(u_int32_t *, u_int32_t *, struct mbuf **, int *);
-#ifdef PULLDOWN_TEST
-static struct mbuf *ip6_pullexthdr(struct mbuf *, size_t, int);
-#endif
 
 /*
  * IP6 initialization: fill in IP6 protocol switch table.
@@ -442,17 +439,8 @@ ip6_input_hbh(struct mbuf **mp, uint32_t *plen, uint32
 			    (caddr_t)&ip6->ip6_plen - (caddr_t)ip6);
 		goto out;
 	}
-#ifndef PULLDOWN_TEST
 	/* ip6_hopopts_input() ensures that mbuf is contiguous */
 	hbh = (struct ip6_hbh *)(ip6 + 1);
-#else
-	IP6_EXTHDR_GET(hbh, struct ip6_hbh *, m, sizeof(struct ip6_hdr),
-		sizeof(struct ip6_hbh));
-	if (hbh == NULL) {
-		IP6STAT_INC(ip6s_tooshort);
-		goto out;
-	}
-#endif
 	*nxt = hbh->ip6h_nxt;
 
 	/*
@@ -603,7 +591,6 @@ ip6_input(struct mbuf *m)

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***


More information about the svn-src-all mailing list