Date: Fri, 10 Jan 2020 23:46:12 +0000 (UTC) From: "Bjoern A. Zeeb" <bz@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-12@freebsd.org Subject: svn commit: r356619 - in stable/12: sys/netinet sys/netinet6 sys/netipsec tests/sys/netinet6 Message-ID: <202001102346.00ANkCuU047753@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
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 ***
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202001102346.00ANkCuU047753>