ip: fix cancel termination after receive malformed ip6 packet 83/22683/7
authorjohny <jan.cavojsky@pantheon.tech>
Fri, 11 Oct 2019 16:28:51 +0000 (18:28 +0200)
committerOle Trøan <otroan@employees.org>
Thu, 5 Dec 2019 15:13:48 +0000 (15:13 +0000)
This fix is for cancel termination of vpp after receive malformed
packet type of ip6.To avoid termination of vpp are checked if are
missing data in packet. This occours, when payload length in ip6
header packet is more than real count of data in packet. When
this error occours, packet is ignore.

Type: fix
Ticket: VPP-1693, VPP-1694

Change-Id: I9d9ecea7b75c8702cb31aa8051c8d4d7ce19659d
Signed-off-by: johny <jan.cavojsky@pantheon.tech>
src/vnet/ip/ip.h
src/vnet/ip/ip6_forward.c

index 22daaab..587ec85 100644 (file)
@@ -213,7 +213,6 @@ ip_calculate_l4_checksum (vlib_main_t * vm, vlib_buffer_t * p0,
              n_this_buffer = n_ip_bytes_this_buffer - ip_header_size;
              if (PREDICT_FALSE (n_this_buffer >> 31))
                {               /*  error - ip header don't fit this buffer */
-                 ASSERT (0);
                  return 0xfefe;
                }
            }
@@ -235,7 +234,6 @@ ip_calculate_l4_checksum (vlib_main_t * vm, vlib_buffer_t * p0,
 
       if (!(p0->flags & VLIB_BUFFER_NEXT_PRESENT))
        {
-         ASSERT (0);           /* error - more buffer expected */
          return 0xfefe;
        }
 
index ae7083b..959ff89 100644 (file)
@@ -1136,6 +1136,52 @@ VNET_FEATURE_ARC_INIT (ip6_local) =
 };
 /* *INDENT-ON* */
 
+static_always_inline u8
+ip6_tcp_udp_icmp_bad_length (vlib_main_t * vm, vlib_buffer_t * p0)
+{
+
+  u16 payload_length_host_byte_order;
+  u32 n_this_buffer, n_bytes_left;
+  ip6_header_t *ip0 = vlib_buffer_get_current (p0);
+  u32 headers_size = sizeof (ip0[0]);
+  u8 *data_this_buffer;
+
+
+  data_this_buffer = (u8 *) (ip0 + 1);
+
+  ip6_hop_by_hop_ext_t *ext_hdr = (ip6_hop_by_hop_ext_t *) data_this_buffer;
+
+  /* validate really icmp6 next */
+
+  if (!(ext_hdr->next_hdr == IP_PROTOCOL_ICMP6)
+      || (ext_hdr->next_hdr == IP_PROTOCOL_UDP))
+    return 0;
+
+
+  payload_length_host_byte_order = clib_net_to_host_u16 (ip0->payload_length);
+  n_bytes_left = n_this_buffer = payload_length_host_byte_order;
+
+  if (p0)
+    {
+      u32 n_ip_bytes_this_buffer =
+       p0->current_length - (((u8 *) ip0 - p0->data) - p0->current_data);
+      if (n_this_buffer + headers_size > n_ip_bytes_this_buffer)
+       {
+         n_this_buffer = p0->current_length > headers_size ?
+           n_ip_bytes_this_buffer - headers_size : 0;
+       }
+    }
+
+  n_bytes_left -= n_this_buffer;
+  n_bytes_left -= p0->total_length_not_including_first_buffer;
+
+  if (n_bytes_left == 0)
+    return 0;
+  else
+    return 1;
+}
+
+
 always_inline uword
 ip6_local_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
                  vlib_frame_t * frame, int head_of_feature_arc)
@@ -1250,16 +1296,28 @@ ip6_local_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
            {
              flags[0] = ip6_tcp_udp_icmp_validate_checksum (vm, b[0]);
              good_l4_csum[0] = flags[0] & VNET_BUFFER_F_L4_CHECKSUM_CORRECT;
+             error[0] = IP6_ERROR_UNKNOWN_PROTOCOL;
+           }
+         else
+           {
+             if (ip6_tcp_udp_icmp_bad_length (vm, b[0]))
+               error[0] = IP6_ERROR_BAD_LENGTH;
            }
          if (PREDICT_FALSE (need_csum[1]))
            {
              flags[1] = ip6_tcp_udp_icmp_validate_checksum (vm, b[1]);
              good_l4_csum[1] = flags[1] & VNET_BUFFER_F_L4_CHECKSUM_CORRECT;
+             error[1] = IP6_ERROR_UNKNOWN_PROTOCOL;
+           }
+         else
+           {
+             if (ip6_tcp_udp_icmp_bad_length (vm, b[1]))
+               error[1] = IP6_ERROR_BAD_LENGTH;
            }
 
-         error[0] = IP6_ERROR_UNKNOWN_PROTOCOL;
+
          error[0] = len_diff[0] < 0 ? IP6_ERROR_UDP_LENGTH : error[0];
-         error[1] = IP6_ERROR_UNKNOWN_PROTOCOL;
+
          error[1] = len_diff[1] < 0 ? IP6_ERROR_UDP_LENGTH : error[1];
 
          STATIC_ASSERT (IP6_ERROR_UDP_CHECKSUM + IP_BUILTIN_PROTOCOL_UDP ==
@@ -1391,9 +1449,16 @@ ip6_local_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
            {
              flags = ip6_tcp_udp_icmp_validate_checksum (vm, b[0]);
              good_l4_csum = flags & VNET_BUFFER_F_L4_CHECKSUM_CORRECT;
+             error = IP6_ERROR_UNKNOWN_PROTOCOL;
            }
+         else
+           {
+             if (ip6_tcp_udp_icmp_bad_length (vm, b[0]))
+               error = IP6_ERROR_BAD_LENGTH;
+           }
+
+
 
-         error = IP6_ERROR_UNKNOWN_PROTOCOL;
          error = len_diff < 0 ? IP6_ERROR_UDP_LENGTH : error;
 
          STATIC_ASSERT (IP6_ERROR_UDP_CHECKSUM + IP_BUILTIN_PROTOCOL_UDP ==