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