Print this page
9832 Original bug discovered as 9560 has friends IPv4 packets coming in as IPv6 creating chaos
Reviewed by: Robert Mustacchi <rm@joyent.com>

*** 18,27 **** --- 18,28 ---- * * CDDL HEADER END */ /* * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright 2019 Joyent, Inc. */ /* * MAC Services Module - misc utilities */
*** 475,485 **** * and next header value (a transport header) is captured. * * Returns B_FALSE if all the IP headers are not in the same mblk otherwise * returns B_TRUE. */ ! boolean_t mac_ip_hdr_length_v6(ip6_t *ip6h, uint8_t *endptr, uint16_t *hdr_length, uint8_t *next_hdr, ip6_frag_t **fragp) { uint16_t length; uint_t ehdrlen; --- 476,486 ---- * and next header value (a transport header) is captured. * * Returns B_FALSE if all the IP headers are not in the same mblk otherwise * returns B_TRUE. */ ! int mac_ip_hdr_length_v6(ip6_t *ip6h, uint8_t *endptr, uint16_t *hdr_length, uint8_t *next_hdr, ip6_frag_t **fragp) { uint16_t length; uint_t ehdrlen;
*** 488,499 **** ip6_dest_t *desthdr; ip6_rthdr_t *rthdr; ip6_frag_t *fraghdr; if (((uchar_t *)ip6h + IPV6_HDR_LEN) > endptr) ! return (B_FALSE); ! ASSERT(IPH_HDR_VERSION(ip6h) == IPV6_VERSION); length = IPV6_HDR_LEN; whereptr = ((uint8_t *)&ip6h[1]); /* point to next hdr */ if (fragp != NULL) *fragp = NULL; --- 489,506 ---- ip6_dest_t *desthdr; ip6_rthdr_t *rthdr; ip6_frag_t *fraghdr; if (((uchar_t *)ip6h + IPV6_HDR_LEN) > endptr) ! return (ENOSPC); ! /* ! * Return EINVAL, which mac_protect callers treat explicitly as "let ! * pass", flow callers treat as "not in a flow", and the rest treat ! * as "don't do special processing". ! */ ! if (IPH_HDR_VERSION(ip6h) != IPV6_VERSION) ! return (EINVAL); length = IPV6_HDR_LEN; whereptr = ((uint8_t *)&ip6h[1]); /* point to next hdr */ if (fragp != NULL) *fragp = NULL;
*** 509,543 **** case IPPROTO_DSTOPTS: /* Assumes the headers are identical for hbh and dst */ desthdr = (ip6_dest_t *)whereptr; ehdrlen = 8 * (desthdr->ip6d_len + 1); if ((uchar_t *)desthdr + ehdrlen > endptr) ! return (B_FALSE); nexthdrp = &desthdr->ip6d_nxt; break; case IPPROTO_ROUTING: rthdr = (ip6_rthdr_t *)whereptr; ehdrlen = 8 * (rthdr->ip6r_len + 1); if ((uchar_t *)rthdr + ehdrlen > endptr) ! return (B_FALSE); nexthdrp = &rthdr->ip6r_nxt; break; case IPPROTO_FRAGMENT: fraghdr = (ip6_frag_t *)whereptr; ehdrlen = sizeof (ip6_frag_t); if ((uchar_t *)&fraghdr[1] > endptr) ! return (B_FALSE); nexthdrp = &fraghdr->ip6f_nxt; if (fragp != NULL) *fragp = fraghdr; break; case IPPROTO_NONE: /* No next header means we're finished */ default: *hdr_length = length; *next_hdr = *nexthdrp; ! return (B_TRUE); } length += ehdrlen; whereptr += ehdrlen; *hdr_length = length; *next_hdr = *nexthdrp; --- 516,550 ---- case IPPROTO_DSTOPTS: /* Assumes the headers are identical for hbh and dst */ desthdr = (ip6_dest_t *)whereptr; ehdrlen = 8 * (desthdr->ip6d_len + 1); if ((uchar_t *)desthdr + ehdrlen > endptr) ! return (ENOSPC); nexthdrp = &desthdr->ip6d_nxt; break; case IPPROTO_ROUTING: rthdr = (ip6_rthdr_t *)whereptr; ehdrlen = 8 * (rthdr->ip6r_len + 1); if ((uchar_t *)rthdr + ehdrlen > endptr) ! return (ENOSPC); nexthdrp = &rthdr->ip6r_nxt; break; case IPPROTO_FRAGMENT: fraghdr = (ip6_frag_t *)whereptr; ehdrlen = sizeof (ip6_frag_t); if ((uchar_t *)&fraghdr[1] > endptr) ! return (ENOSPC); nexthdrp = &fraghdr->ip6f_nxt; if (fragp != NULL) *fragp = fraghdr; break; case IPPROTO_NONE: /* No next header means we're finished */ default: *hdr_length = length; *next_hdr = *nexthdrp; ! return (0); } length += ehdrlen; whereptr += ehdrlen; *hdr_length = length; *next_hdr = *nexthdrp;
*** 549,569 **** case IPPROTO_FRAGMENT: /* * If any know extension headers are still to be processed, * the packet's malformed (or at least all the IP header(s) are * not in the same mblk - and that should never happen. */ ! return (B_FALSE); default: /* * If we get here, we know that all of the IP headers were in * the same mblk, even if the ULP header is in the next mblk. */ *hdr_length = length; *next_hdr = *nexthdrp; ! return (B_TRUE); } } /* * The following set of routines are there to take care of interrupt --- 556,579 ---- case IPPROTO_FRAGMENT: /* * If any know extension headers are still to be processed, * the packet's malformed (or at least all the IP header(s) are * not in the same mblk - and that should never happen. + * + * Return ENOSPC because it MAY be spread across mblks, and + * and the rest of MAC or IPv6 itself can cope. */ ! return (ENOSPC); default: /* * If we get here, we know that all of the IP headers were in * the same mblk, even if the ULP header is in the next mblk. */ *hdr_length = length; *next_hdr = *nexthdrp; ! return (0); } } /* * The following set of routines are there to take care of interrupt
*** 966,982 **** switch (sap) { case ETHERTYPE_IP: { ipha_t *iphp; /* ! * If the header is not aligned or the header doesn't fit ! * in the mblk, bail now. Note that this may cause packets ! * reordering. */ iphp = (ipha_t *)(mp->b_rptr + skip_len); if (((unsigned char *)iphp + sizeof (ipha_t) > mp->b_wptr) || ! !OK_32PTR((char *)iphp)) goto done; proto = iphp->ipha_protocol; skip_len += IPH_HDR_LENGTH(iphp); --- 976,993 ---- switch (sap) { case ETHERTYPE_IP: { ipha_t *iphp; /* ! * If the header is not aligned, the header doesn't fit in the ! * mblk, OR we have a bad IP version, bail now. Note that this ! * may cause packets reordering. */ iphp = (ipha_t *)(mp->b_rptr + skip_len); if (((unsigned char *)iphp + sizeof (ipha_t) > mp->b_wptr) || ! !OK_32PTR((char *)iphp) || ! IPH_HDR_VERSION(iphp) != IPV4_VERSION) goto done; proto = iphp->ipha_protocol; skip_len += IPH_HDR_LENGTH(iphp);
*** 1019,1030 **** ip6hp = (ip6_t *)(mp->b_rptr + skip_len); if (((unsigned char *)ip6hp + IPV6_HDR_LEN > mp->b_wptr) || !OK_32PTR((char *)ip6hp)) goto done; ! if (!mac_ip_hdr_length_v6(ip6hp, mp->b_wptr, &hdr_length, ! &proto, &frag)) goto done; skip_len += hdr_length; /* * For fragmented packets, use addresses in addition to --- 1030,1042 ---- ip6hp = (ip6_t *)(mp->b_rptr + skip_len); if (((unsigned char *)ip6hp + IPV6_HDR_LEN > mp->b_wptr) || !OK_32PTR((char *)ip6hp)) goto done; ! /* Also bail, regardless of why, if the function below fails. */ ! if (mac_ip_hdr_length_v6(ip6hp, mp->b_wptr, &hdr_length, ! &proto, &frag) != 0) goto done; skip_len += hdr_length; /* * For fragmented packets, use addresses in addition to