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,10 +18,11 @@
  *
  * 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,11 +476,11 @@
  * 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
+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,12 +489,18 @@
         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);
+                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,35 +516,35 @@
                 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);
+                                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 (B_FALSE);
+                                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 (B_FALSE);
+                                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 (B_TRUE);
+                        return (0);
                 }
                 length += ehdrlen;
                 whereptr += ehdrlen;
                 *hdr_length = length;
                 *next_hdr = *nexthdrp;

@@ -549,21 +556,24 @@
         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 (B_FALSE);
+                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 (B_TRUE);
+                return (0);
         }
 }
 
 /*
  * The following set of routines are there to take care of interrupt

@@ -966,17 +976,18 @@
         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.
+                 * 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))
+                    !OK_32PTR((char *)iphp) ||
+                    IPH_HDR_VERSION(iphp) != IPV4_VERSION)
                         goto done;
 
                 proto = iphp->ipha_protocol;
                 skip_len += IPH_HDR_LENGTH(iphp);
 

@@ -1019,12 +1030,13 @@
                 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))
+                /* 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