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>

Split Close
Expand all
Collapse all
          --- old/usr/src/uts/common/io/mac/mac_util.c
          +++ new/usr/src/uts/common/io/mac/mac_util.c
↓ open down ↓ 12 lines elided ↑ open up ↑
  13   13   * When distributing Covered Code, include this CDDL HEADER in each
  14   14   * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15   15   * If applicable, add the following below this CDDL HEADER, with the
  16   16   * fields enclosed by brackets "[]" replaced with your own identifying
  17   17   * information: Portions Copyright [yyyy] [name of copyright owner]
  18   18   *
  19   19   * CDDL HEADER END
  20   20   */
  21   21  /*
  22   22   * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
       23 + * Copyright 2019 Joyent, Inc.
  23   24   */
  24   25  
  25   26  /*
  26   27   * MAC Services Module - misc utilities
  27   28   */
  28   29  
  29   30  #include <sys/types.h>
  30   31  #include <sys/mac.h>
  31   32  #include <sys/mac_impl.h>
  32   33  #include <sys/mac_client_priv.h>
↓ open down ↓ 437 lines elided ↑ open up ↑
 470  471  }
 471  472  
 472  473  /*
 473  474   * Determines the IPv6 header length accounting for all the optional IPv6
 474  475   * headers (hop-by-hop, destination, routing and fragment). The header length
 475  476   * and next header value (a transport header) is captured.
 476  477   *
 477  478   * Returns B_FALSE if all the IP headers are not in the same mblk otherwise
 478  479   * returns B_TRUE.
 479  480   */
 480      -boolean_t
      481 +int
 481  482  mac_ip_hdr_length_v6(ip6_t *ip6h, uint8_t *endptr, uint16_t *hdr_length,
 482  483      uint8_t *next_hdr, ip6_frag_t **fragp)
 483  484  {
 484  485          uint16_t length;
 485  486          uint_t  ehdrlen;
 486  487          uint8_t *whereptr;
 487  488          uint8_t *nexthdrp;
 488  489          ip6_dest_t *desthdr;
 489  490          ip6_rthdr_t *rthdr;
 490  491          ip6_frag_t *fraghdr;
 491  492  
 492  493          if (((uchar_t *)ip6h + IPV6_HDR_LEN) > endptr)
 493      -                return (B_FALSE);
 494      -        ASSERT(IPH_HDR_VERSION(ip6h) == IPV6_VERSION);
      494 +                return (ENOSPC);
      495 +        /*
      496 +         * Return EINVAL, which mac_protect callers treat explicitly as "let
      497 +         * pass", flow callers treat as "not in a flow", and the rest treat
      498 +         * as "don't do special processing".
      499 +         */
      500 +        if (IPH_HDR_VERSION(ip6h) != IPV6_VERSION)
      501 +                return (EINVAL);
 495  502          length = IPV6_HDR_LEN;
 496  503          whereptr = ((uint8_t *)&ip6h[1]); /* point to next hdr */
 497  504  
 498  505          if (fragp != NULL)
 499  506                  *fragp = NULL;
 500  507  
 501  508          nexthdrp = &ip6h->ip6_nxt;
 502  509          while (whereptr < endptr) {
 503  510                  /* Is there enough left for len + nexthdr? */
 504  511                  if (whereptr + MIN_EHDR_LEN > endptr)
 505  512                          break;
 506  513  
 507  514                  switch (*nexthdrp) {
 508  515                  case IPPROTO_HOPOPTS:
 509  516                  case IPPROTO_DSTOPTS:
 510  517                          /* Assumes the headers are identical for hbh and dst */
 511  518                          desthdr = (ip6_dest_t *)whereptr;
 512  519                          ehdrlen = 8 * (desthdr->ip6d_len + 1);
 513  520                          if ((uchar_t *)desthdr +  ehdrlen > endptr)
 514      -                                return (B_FALSE);
      521 +                                return (ENOSPC);
 515  522                          nexthdrp = &desthdr->ip6d_nxt;
 516  523                          break;
 517  524                  case IPPROTO_ROUTING:
 518  525                          rthdr = (ip6_rthdr_t *)whereptr;
 519  526                          ehdrlen =  8 * (rthdr->ip6r_len + 1);
 520  527                          if ((uchar_t *)rthdr +  ehdrlen > endptr)
 521      -                                return (B_FALSE);
      528 +                                return (ENOSPC);
 522  529                          nexthdrp = &rthdr->ip6r_nxt;
 523  530                          break;
 524  531                  case IPPROTO_FRAGMENT:
 525  532                          fraghdr = (ip6_frag_t *)whereptr;
 526  533                          ehdrlen = sizeof (ip6_frag_t);
 527  534                          if ((uchar_t *)&fraghdr[1] > endptr)
 528      -                                return (B_FALSE);
      535 +                                return (ENOSPC);
 529  536                          nexthdrp = &fraghdr->ip6f_nxt;
 530  537                          if (fragp != NULL)
 531  538                                  *fragp = fraghdr;
 532  539                          break;
 533  540                  case IPPROTO_NONE:
 534  541                          /* No next header means we're finished */
 535  542                  default:
 536  543                          *hdr_length = length;
 537  544                          *next_hdr = *nexthdrp;
 538      -                        return (B_TRUE);
      545 +                        return (0);
 539  546                  }
 540  547                  length += ehdrlen;
 541  548                  whereptr += ehdrlen;
 542  549                  *hdr_length = length;
 543  550                  *next_hdr = *nexthdrp;
 544  551          }
 545  552          switch (*nexthdrp) {
 546  553          case IPPROTO_HOPOPTS:
 547  554          case IPPROTO_DSTOPTS:
 548  555          case IPPROTO_ROUTING:
 549  556          case IPPROTO_FRAGMENT:
 550  557                  /*
 551  558                   * If any know extension headers are still to be processed,
 552  559                   * the packet's malformed (or at least all the IP header(s) are
 553  560                   * not in the same mblk - and that should never happen.
      561 +                 *
      562 +                 * Return ENOSPC because it MAY be spread across mblks, and
      563 +                 * and the rest of MAC or IPv6 itself can cope.
 554  564                   */
 555      -                return (B_FALSE);
      565 +                return (ENOSPC);
 556  566  
 557  567          default:
 558  568                  /*
 559  569                   * If we get here, we know that all of the IP headers were in
 560  570                   * the same mblk, even if the ULP header is in the next mblk.
 561  571                   */
 562  572                  *hdr_length = length;
 563  573                  *next_hdr = *nexthdrp;
 564      -                return (B_TRUE);
      574 +                return (0);
 565  575          }
 566  576  }
 567  577  
 568  578  /*
 569  579   * The following set of routines are there to take care of interrupt
 570  580   * re-targeting for legacy (fixed) interrupts. Some older versions
 571  581   * of the popular NICs like e1000g do not support MSI-X interrupts
 572  582   * and they reserve fixed interrupts for RX/TX rings. To re-target
 573  583   * these interrupts, PCITOOL ioctls need to be used.
 574  584   */
↓ open down ↓ 386 lines elided ↑ open up ↑
 961  971  
 962  972          sap = (sap < ETHERTYPE_802_MIN) ? 0 : sap;
 963  973  
 964  974          /* compute IP src/dst addresses hash and skip IPv{4,6} header */
 965  975  
 966  976          switch (sap) {
 967  977          case ETHERTYPE_IP: {
 968  978                  ipha_t *iphp;
 969  979  
 970  980                  /*
 971      -                 * If the header is not aligned or the header doesn't fit
 972      -                 * in the mblk, bail now. Note that this may cause packets
 973      -                 * reordering.
      981 +                 * If the header is not aligned, the header doesn't fit in the
      982 +                 * mblk, OR we have a bad IP version, bail now. Note that this
      983 +                 * may cause packets reordering.
 974  984                   */
 975  985                  iphp = (ipha_t *)(mp->b_rptr + skip_len);
 976  986                  if (((unsigned char *)iphp + sizeof (ipha_t) > mp->b_wptr) ||
 977      -                    !OK_32PTR((char *)iphp))
      987 +                    !OK_32PTR((char *)iphp) ||
      988 +                    IPH_HDR_VERSION(iphp) != IPV4_VERSION)
 978  989                          goto done;
 979  990  
 980  991                  proto = iphp->ipha_protocol;
 981  992                  skip_len += IPH_HDR_LENGTH(iphp);
 982  993  
 983  994                  /* Check if the packet is fragmented. */
 984  995                  ip_fragmented = ntohs(iphp->ipha_fragment_offset_and_flags) &
 985  996                      IPH_OFFSET;
 986  997  
 987  998                  /*
↓ open down ↓ 26 lines elided ↑ open up ↑
1014 1025                   * If the header is not aligned or the header doesn't fit
1015 1026                   * in the mblk, bail now. Note that this may cause packets
1016 1027                   * reordering.
1017 1028                   */
1018 1029  
1019 1030                  ip6hp = (ip6_t *)(mp->b_rptr + skip_len);
1020 1031                  if (((unsigned char *)ip6hp + IPV6_HDR_LEN > mp->b_wptr) ||
1021 1032                      !OK_32PTR((char *)ip6hp))
1022 1033                          goto done;
1023 1034  
1024      -                if (!mac_ip_hdr_length_v6(ip6hp, mp->b_wptr, &hdr_length,
1025      -                    &proto, &frag))
     1035 +                /* Also bail, regardless of why, if the function below fails. */
     1036 +                if (mac_ip_hdr_length_v6(ip6hp, mp->b_wptr, &hdr_length,
     1037 +                    &proto, &frag) != 0)
1026 1038                          goto done;
1027 1039                  skip_len += hdr_length;
1028 1040  
1029 1041                  /*
1030 1042                   * For fragmented packets, use addresses in addition to
1031 1043                   * the frag_id to generate the hash inorder to get
1032 1044                   * better distribution.
1033 1045                   */
1034 1046                  if (frag != NULL || (policy & MAC_PKT_HASH_L3) != 0) {
1035 1047                          uint8_t *ip_src = &(ip6hp->ip6_src.s6_addr8[12]);
↓ open down ↓ 71 lines elided ↑ open up ↑
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX