From a4adf6cc653fa8ed9b1d06052f00b2481688d711 Mon Sep 17 00:00:00 2001 From: "Bjoern A. Zeeb" Date: Sun, 1 Dec 2019 00:22:04 +0000 Subject: [PATCH] Fix m_pullup() problem after removing PULLDOWN_TESTs and KAME EXT_*macros. r354748-354750 replaced the KAME macros with m_pulldown() calls. Contrary to the rest of the network stack m_len checks before m_pulldown() were not put in placed (see r354748). Put these m_len checks in place for now (to go along with the style of the network stack since the initial commits). These are not put in for performance but to avoid an error scenario (even though it also will help performance at the moment as it avoid allocating an extra mbuf; not because of the unconditional function call). The observed error case went like this: (1) an mbuf with M_EXT arrives and we call m_pullup() unconditionally on it. (2) m_pullup() will call m_get() unless the requested length is larger than MHLEN (in which case it'll m_freem() the perfectly fine mbuf) and migrate the requested length of data and pkthdr into the new mbuf. (3) If m_get() succeeds, a further m_pullup() call going over MHLEN will fail. This was observed with failing auto-configuration as an RA packet of 200 bytes exceeded MHLEN and the m_pullup() called from nd6_ra_input() dropped the mbuf. (Re-)adding the m_len checks before m_pullup() calls avoids this problems with mbufs using external storage for now. MFC after: 3 weeks Sponsored by: Netflix --- sys/netinet/ip_carp.c | 14 ++-- sys/netinet/tcp_input.c | 22 +++--- sys/netinet6/dest6.c | 24 +++--- sys/netinet6/frag6.c | 12 +-- sys/netinet6/icmp6.c | 143 ++++++++++++++++++++++-------------- sys/netinet6/ip6_input.c | 24 +++--- sys/netinet6/ip6_mroute.c | 10 ++- sys/netinet6/mld6.c | 20 +++-- sys/netinet6/nd6_nbr.c | 20 +++-- sys/netinet6/nd6_rtr.c | 20 +++-- sys/netinet6/route6.c | 12 +-- sys/netinet6/sctp6_usrreq.c | 10 ++- sys/netinet6/udp6_usrreq.c | 12 +-- sys/netipsec/xform_ah.c | 14 ++-- sys/netipsec/xform_esp.c | 14 ++-- 15 files changed, 220 insertions(+), 151 deletions(-) diff --git a/sys/netinet/ip_carp.c b/sys/netinet/ip_carp.c index d783c93a2abf..e5db364c8f6d 100644 --- a/sys/netinet/ip_carp.c +++ b/sys/netinet/ip_carp.c @@ -566,12 +566,14 @@ carp6_input(struct mbuf **mp, int *offp, int proto) } /* verify that we have a complete carp packet */ - 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); + 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); diff --git a/sys/netinet/tcp_input.c b/sys/netinet/tcp_input.c index 8d68770f5cb4..8e8c8b79a458 100644 --- a/sys/netinet/tcp_input.c +++ b/sys/netinet/tcp_input.c @@ -517,11 +517,13 @@ tcp6_input(struct mbuf **mp, int *offp, int proto) struct ip6_hdr *ip6; m = *mp; - m = m_pullup(m, *offp + sizeof(struct tcphdr)); - if (m == NULL) { - *mp = m; - TCPSTAT_INC(tcps_rcvshort); - return (IPPROTO_DONE); + 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); + } } /* @@ -708,10 +710,12 @@ tcp_input(struct mbuf **mp, int *offp, int proto) if (off > sizeof (struct tcphdr)) { #ifdef INET6 if (isipv6) { - m = m_pullup(m, off0 + off); - if (m == NULL) { - TCPSTAT_INC(tcps_rcvshort); - return (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); diff --git a/sys/netinet6/dest6.c b/sys/netinet6/dest6.c index 3ec199138b6c..09b84f589543 100644 --- a/sys/netinet6/dest6.c +++ b/sys/netinet6/dest6.c @@ -73,20 +73,24 @@ dest6_input(struct mbuf **mp, int *offp, int proto) off = *offp; /* Validation of the length of the header. */ - m = m_pullup(m, off + sizeof(*dstopts)); - if (m == NULL) { - IP6STAT_INC(ip6s_exthdrtoolong); - *mp = m; - return (IPPROTO_DONE); + 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); dstoptlen = (dstopts->ip6d_len + 1) << 3; - m = m_pullup(m, off + dstoptlen); - if (m == NULL) { - IP6STAT_INC(ip6s_exthdrtoolong); - *mp = m; - return (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); off += dstoptlen; diff --git a/sys/netinet6/frag6.c b/sys/netinet6/frag6.c index 25e124adf4d3..15b2c2a14af0 100644 --- a/sys/netinet6/frag6.c +++ b/sys/netinet6/frag6.c @@ -389,11 +389,13 @@ frag6_input(struct mbuf **mp, int *offp, int proto) M_ASSERTPKTHDR(m); - m = m_pullup(m, offset + sizeof(struct ip6_frag)); - if (m == NULL) { - IP6STAT_INC(ip6s_exthdrtoolong); - *mp = NULL; - return (IPPROTO_DONE); + 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 *); diff --git a/sys/netinet6/icmp6.c b/sys/netinet6/icmp6.c index 92624bf43042..141da4e658d6 100644 --- a/sys/netinet6/icmp6.c +++ b/sys/netinet6/icmp6.c @@ -317,10 +317,12 @@ icmp6_error(struct mbuf *m, int type, int code, int param) if (off >= 0 && nxt == IPPROTO_ICMPV6) { struct icmp6_hdr *icp; - m = m_pullup(m, off + sizeof(struct icmp6_hdr)); - if (m == NULL) { - IP6STAT_INC(ip6s_exthdrtoolong); - 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; + } } oip6 = mtod(m, struct ip6_hdr *); icp = (struct icmp6_hdr *)(mtod(m, caddr_t) + off); @@ -401,11 +403,13 @@ icmp6_input(struct mbuf **mp, int *offp, int proto) m = *mp; off = *offp; - m = m_pullup(m, off + sizeof(struct icmp6_hdr)); - if (m == NULL) { - IP6STAT_INC(ip6s_exthdrtoolong); - *mp = m; - return (IPPROTO_DONE); + 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); + } } /* @@ -566,10 +570,12 @@ icmp6_input(struct mbuf **mp, int *offp, int proto) n->m_pkthdr.len = n0len + (noff - off); n->m_next = n0; } else { - n = m_pullup(n, off + sizeof(*nicmp6)); - if (n == NULL) { - IP6STAT_INC(ip6s_exthdrtoolong); - break; + 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; @@ -635,11 +641,14 @@ icmp6_input(struct mbuf **mp, int *offp, int proto) if (pr == NULL) pr = curthread->td_ucred->cr_prison; if (mode == FQDN) { - m = m_pullup(m, off + sizeof(struct icmp6_nodeinfo)); - if (m == NULL) { - IP6STAT_INC(ip6s_exthdrtoolong); - *mp = m; - return (IPPROTO_DONE); + 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) @@ -725,11 +734,13 @@ icmp6_input(struct mbuf **mp, int *offp, int proto) if (icmp6len < sizeof(struct nd_router_solicit)) goto badlen; if (send_sendso_input_hook != NULL) { - m = m_pullup(m, off + icmp6len); - if (m == NULL) { - IP6STAT_INC(ip6s_exthdrtoolong); - *mp = NULL; - return (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) { @@ -891,11 +902,13 @@ icmp6_notify_error(struct mbuf **mp, int off, int icmp6len, int code) goto freeit; } - m = m_pullup(m, off + sizeof(*icmp6) + sizeof(struct ip6_hdr)); - if (m == NULL) { - IP6STAT_INC(ip6s_exthdrtoolong); - *mp = m; - 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); + } } icmp6 = (struct icmp6_hdr *)(mtod(m, caddr_t) + off); eip6 = (struct ip6_hdr *)(icmp6 + 1); @@ -921,11 +934,14 @@ icmp6_notify_error(struct mbuf **mp, int off, int icmp6len, int code) case IPPROTO_HOPOPTS: case IPPROTO_DSTOPTS: case IPPROTO_AH: - m = m_pullup(m, eoff + sizeof(struct ip6_ext)); - if (m == NULL) { - IP6STAT_INC(ip6s_exthdrtoolong); - *mp = m; - 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); + } } eh = (struct ip6_ext *) (mtod(m, caddr_t) + eoff); @@ -944,11 +960,13 @@ icmp6_notify_error(struct mbuf **mp, int off, int icmp6len, int code) * information that depends on the final * destination (e.g. path MTU). */ - m = m_pullup(m, eoff + sizeof(*rth)); - if (m == NULL) { - IP6STAT_INC(ip6s_exthdrtoolong); - *mp = m; - return (-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); @@ -965,11 +983,14 @@ icmp6_notify_error(struct mbuf **mp, int off, int icmp6len, int code) rth->ip6r_type == IPV6_RTHDR_TYPE_0) { int hops; - m = m_pullup(m, eoff + rthlen); - if (m == NULL) { - IP6STAT_INC(ip6s_exthdrtoolong); - *mp = m; - return (-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); @@ -982,11 +1003,14 @@ icmp6_notify_error(struct mbuf **mp, int off, int icmp6len, int code) nxt = rth->ip6r_nxt; break; case IPPROTO_FRAGMENT: - m = m_pullup(m, eoff + sizeof(struct ip6_frag)); - if (m == NULL) { - IP6STAT_INC(ip6s_exthdrtoolong); - *mp = m; - return (-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); @@ -1295,11 +1319,14 @@ ni6_input(struct mbuf *m, int off, struct prison *pr) mtx_unlock(&pr->pr_mtx); if (!n || n->m_next || n->m_len == 0) goto bad; - m = m_pullup(m, off + sizeof(struct icmp6_nodeinfo) + - subjlen); - if (m == NULL) { - IP6STAT_INC(ip6s_exthdrtoolong); - 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); @@ -2201,10 +2228,12 @@ icmp6_redirect_input(struct mbuf *m, int off) ip6 = mtod(m, struct ip6_hdr *); icmp6len = ntohs(ip6->ip6_plen); - m = m_pullup(m, off + icmp6len); - if (m == NULL) { - IP6STAT_INC(ip6s_exthdrtoolong); - return; + if (m->m_len < off + icmp6len) { + m = m_pullup(m, off + icmp6len); + if (m == NULL) { + IP6STAT_INC(ip6s_exthdrtoolong); + return; + } } ip6 = mtod(m, struct ip6_hdr *); nd_rd = (struct nd_redirect *)((caddr_t)ip6 + off); diff --git a/sys/netinet6/ip6_input.c b/sys/netinet6/ip6_input.c index 8cf38525a0dc..22797ff5d3ba 100644 --- a/sys/netinet6/ip6_input.c +++ b/sys/netinet6/ip6_input.c @@ -969,20 +969,24 @@ ip6_hopopts_input(u_int32_t *plenp, u_int32_t *rtalertp, struct ip6_hbh *hbh; /* validation of the length of the header */ - m = m_pullup(m, off + sizeof(*hbh)); - if (m == NULL) { - IP6STAT_INC(ip6s_exthdrtoolong); - *mp = NULL; - return (-1); + if (m->m_len < off + sizeof(*hbh)) { + m = m_pullup(m, off + sizeof(*hbh)); + if (m == NULL) { + IP6STAT_INC(ip6s_exthdrtoolong); + *mp = NULL; + return (-1); + } } hbh = (struct ip6_hbh *)(mtod(m, caddr_t) + off); hbhlen = (hbh->ip6h_len + 1) << 3; - m = m_pullup(m, off + hbhlen); - if (m == NULL) { - IP6STAT_INC(ip6s_exthdrtoolong); - *mp = NULL; - return (-1); + if (m->m_len < off + hbhlen) { + m = m_pullup(m, off + hbhlen); + if (m == NULL) { + IP6STAT_INC(ip6s_exthdrtoolong); + *mp = NULL; + return (-1); + } } hbh = (struct ip6_hbh *)(mtod(m, caddr_t) + off); off += hbhlen; diff --git a/sys/netinet6/ip6_mroute.c b/sys/netinet6/ip6_mroute.c index 660c2ef848b3..82ca908d4553 100644 --- a/sys/netinet6/ip6_mroute.c +++ b/sys/netinet6/ip6_mroute.c @@ -1745,10 +1745,12 @@ pim6_input(struct mbuf *m, int off, int proto, void *arg __unused) * Make sure that the IP6 and PIM headers in contiguous memory, and * possibly the PIM REGISTER header */ - m = m_pullup(m, off + minlen); - if (m == NULL) { - IP6STAT_INC(ip6s_exthdrtoolong); - return (IPPROTO_DONE); + if (m->m_len < off + minlen) { + m = m_pullup(m, off + minlen); + if (m == NULL) { + IP6STAT_INC(ip6s_exthdrtoolong); + return (IPPROTO_DONE); + } } ip6 = mtod(m, struct ip6_hdr *); pim = (struct pim *)((caddr_t)ip6 + off); diff --git a/sys/netinet6/mld6.c b/sys/netinet6/mld6.c index e5cb120fbef4..1698458462fb 100644 --- a/sys/netinet6/mld6.c +++ b/sys/netinet6/mld6.c @@ -1263,10 +1263,12 @@ mld_input(struct mbuf **mp, int off, int icmp6len) ifp = m->m_pkthdr.rcvif; /* Pullup to appropriate size. */ - m = m_pullup(m, off + sizeof(*mld)); - if (m == NULL) { - ICMP6STAT_INC(icp6s_badlen); - return (IPPROTO_DONE); + if (m->m_len < off + sizeof(*mld)) { + m = m_pullup(m, off + sizeof(*mld)); + if (m == NULL) { + ICMP6STAT_INC(icp6s_badlen); + return (IPPROTO_DONE); + } } mld = (struct mld_hdr *)(mtod(m, uint8_t *) + off); if (mld->mld_type == MLD_LISTENER_QUERY && @@ -1275,10 +1277,12 @@ mld_input(struct mbuf **mp, int off, int icmp6len) } else { mldlen = sizeof(struct mld_hdr); } - m = m_pullup(m, off + mldlen); - if (m == NULL) { - ICMP6STAT_INC(icp6s_badlen); - return (IPPROTO_DONE); + if (m->m_len < off + mldlen) { + m = m_pullup(m, off + mldlen); + if (m == NULL) { + ICMP6STAT_INC(icp6s_badlen); + return (IPPROTO_DONE); + } } *mp = m; ip6 = mtod(m, struct ip6_hdr *); diff --git a/sys/netinet6/nd6_nbr.c b/sys/netinet6/nd6_nbr.c index 153b1013ed56..28fefd160fb4 100644 --- a/sys/netinet6/nd6_nbr.c +++ b/sys/netinet6/nd6_nbr.c @@ -148,10 +148,12 @@ nd6_ns_input(struct mbuf *m, int off, int icmp6len) goto bads; } - m = m_pullup(m, off + icmp6len); - if (m == NULL) { - IP6STAT_INC(ip6s_exthdrtoolong); - return; + if (m->m_len < off + icmp6len) { + m = m_pullup(m, off + icmp6len); + if (m == NULL) { + IP6STAT_INC(ip6s_exthdrtoolong); + return; + } } ip6 = mtod(m, struct ip6_hdr *); nd_ns = (struct nd_neighbor_solicit *)((caddr_t)ip6 + off); @@ -652,10 +654,12 @@ nd6_na_input(struct mbuf *m, int off, int icmp6len) goto bad; } - m = m_pullup(m, off + icmp6len); - if (m == NULL) { - IP6STAT_INC(ip6s_exthdrtoolong); - return; + if (m->m_len < off + icmp6len) { + m = m_pullup(m, off + icmp6len); + if (m == NULL) { + IP6STAT_INC(ip6s_exthdrtoolong); + return; + } } ip6 = mtod(m, struct ip6_hdr *); nd_na = (struct nd_neighbor_advert *)((caddr_t)ip6 + off); diff --git a/sys/netinet6/nd6_rtr.c b/sys/netinet6/nd6_rtr.c index d334f977a7ab..2a1a66998d2e 100644 --- a/sys/netinet6/nd6_rtr.c +++ b/sys/netinet6/nd6_rtr.c @@ -190,10 +190,12 @@ nd6_rs_input(struct mbuf *m, int off, int icmp6len) if (IN6_IS_ADDR_UNSPECIFIED(&saddr6)) goto freeit; - m = m_pullup(m, off + icmp6len); - if (m == NULL) { - IP6STAT_INC(ip6s_exthdrtoolong); - return; + if (m->m_len < off + icmp6len) { + m = m_pullup(m, off + icmp6len); + if (m == NULL) { + IP6STAT_INC(ip6s_exthdrtoolong); + return; + } } ip6 = mtod(m, struct ip6_hdr *); nd_rs = (struct nd_router_solicit *)((caddr_t)ip6 + off); @@ -388,10 +390,12 @@ nd6_ra_input(struct mbuf *m, int off, int icmp6len) goto bad; } - m = m_pullup(m, off + icmp6len); - if (m == NULL) { - IP6STAT_INC(ip6s_exthdrtoolong); - return; + if (m->m_len < off + icmp6len) { + m = m_pullup(m, off + icmp6len); + if (m == NULL) { + IP6STAT_INC(ip6s_exthdrtoolong); + return; + } } ip6 = mtod(m, struct ip6_hdr *); nd_ra = (struct nd_router_advert *)((caddr_t)ip6 + off); diff --git a/sys/netinet6/route6.c b/sys/netinet6/route6.c index 4c488cba5f4a..72e42084eacc 100644 --- a/sys/netinet6/route6.c +++ b/sys/netinet6/route6.c @@ -83,11 +83,13 @@ route6_input(struct mbuf **mp, int *offp, int proto) } #endif - m = m_pullup(m, off + sizeof(*rh)); - if (m == NULL) { - IP6STAT_INC(ip6s_exthdrtoolong); - *mp = NULL; - return (IPPROTO_DONE); + if (m->m_len < off + sizeof(*rh)) { + m = m_pullup(m, off + sizeof(*rh)); + if (m == NULL) { + IP6STAT_INC(ip6s_exthdrtoolong); + *mp = NULL; + return (IPPROTO_DONE); + } } ip6 = mtod(m, struct ip6_hdr *); rh = (struct ip6_rthdr *)((caddr_t)ip6 + off); diff --git a/sys/netinet6/sctp6_usrreq.c b/sys/netinet6/sctp6_usrreq.c index e0bb5c8c12ef..dacf01760c6b 100644 --- a/sys/netinet6/sctp6_usrreq.c +++ b/sys/netinet6/sctp6_usrreq.c @@ -103,10 +103,12 @@ sctp6_input_with_port(struct mbuf **i_pak, int *offp, uint16_t port) SCTP_STAT_INCR_COUNTER64(sctps_inpackets); /* Get IP, SCTP, and first chunk header together in the first mbuf. */ offset = iphlen + sizeof(struct sctphdr) + sizeof(struct sctp_chunkhdr); - m = m_pullup(m, offset); - if (m == NULL) { - SCTP_STAT_INCR(sctps_hdrops); - return (IPPROTO_DONE); + if (m->m_len < offset) { + m = m_pullup(m, offset); + if (m == NULL) { + SCTP_STAT_INCR(sctps_hdrops); + return (IPPROTO_DONE); + } } ip6 = mtod(m, struct ip6_hdr *); sh = (struct sctphdr *)(mtod(m, caddr_t) + iphlen); diff --git a/sys/netinet6/udp6_usrreq.c b/sys/netinet6/udp6_usrreq.c index 64e5f6e3551f..124bded74a40 100644 --- a/sys/netinet6/udp6_usrreq.c +++ b/sys/netinet6/udp6_usrreq.c @@ -223,11 +223,13 @@ udp6_input(struct mbuf **mp, int *offp, int proto) ifp = m->m_pkthdr.rcvif; - m = m_pullup(m, off + sizeof(struct udphdr)); - if (m == NULL) { - IP6STAT_INC(ip6s_exthdrtoolong); - *mp = NULL; - return (IPPROTO_DONE); + if (m->m_len < off + sizeof(struct udphdr)) { + m = m_pullup(m, off + sizeof(struct udphdr)); + if (m == NULL) { + IP6STAT_INC(ip6s_exthdrtoolong); + *mp = NULL; + return (IPPROTO_DONE); + } } ip6 = mtod(m, struct ip6_hdr *); uh = (struct udphdr *)((caddr_t)ip6 + off); diff --git a/sys/netipsec/xform_ah.c b/sys/netipsec/xform_ah.c index 2215d4f1c408..2ed9683a0572 100644 --- a/sys/netipsec/xform_ah.c +++ b/sys/netipsec/xform_ah.c @@ -575,12 +575,14 @@ ah_input(struct mbuf *m, struct secasvar *sav, int skip, int protoff) /* Figure out header size. */ rplen = HDRSIZE(sav); - m = m_pullup(m, skip + rplen); - if (m == NULL) { - DPRINTF(("ah_input: cannot pullup header\n")); - AHSTAT_INC(ahs_hdrops); /*XXX*/ - error = ENOBUFS; - goto bad; + if (m->m_len < skip + rplen) { + m = m_pullup(m, skip + rplen); + if (m == NULL) { + DPRINTF(("ah_input: cannot pullup header\n")); + AHSTAT_INC(ahs_hdrops); /*XXX*/ + error = ENOBUFS; + goto bad; + } } ah = (struct newah *)(mtod(m, caddr_t) + skip); diff --git a/sys/netipsec/xform_esp.c b/sys/netipsec/xform_esp.c index 918d98b6af22..235d87ae1d98 100644 --- a/sys/netipsec/xform_esp.c +++ b/sys/netipsec/xform_esp.c @@ -308,12 +308,14 @@ esp_input(struct mbuf *m, struct secasvar *sav, int skip, int protoff) goto bad; } - m = m_pullup(m, skip + sizeof(*esp)); - if (m == NULL) { - DPRINTF(("%s: cannot pullup header\n", __func__)); - ESPSTAT_INC(esps_hdrops); /*XXX*/ - error = ENOBUFS; - goto bad; + if (m->m_len < skip + sizeof(*esp)) { + m = m_pullup(m, skip + sizeof(*esp)); + if (m == NULL) { + DPRINTF(("%s: cannot pullup header\n", __func__)); + ESPSTAT_INC(esps_hdrops); /*XXX*/ + error = ENOBUFS; + goto bad; + } } esp = (struct newesp *)(mtod(m, caddr_t) + skip);