From 402ed3128512efc091a560729ce1e772a86e9f74 Mon Sep 17 00:00:00 2001 From: Klement Sekera Date: Wed, 18 Jan 2017 09:44:36 +0100 Subject: BFD: improve finding of ipv4/ipv6 headers Avoid coverity warning and improve safety by declaring a helper structure and working with it when searching for ip headers. Make sure the content following IPv6 header is actually UDP before parsing it. Bail out if unexpcted IPv6 header found ... Change-Id: I1c6b9fd42d6fdae226f12c91c53c07a932b29522 Signed-off-by: Klement Sekera --- src/vnet/bfd/bfd_udp.c | 110 ++++++++++++++++++++++++++++--------------------- 1 file changed, 62 insertions(+), 48 deletions(-) (limited to 'src') diff --git a/src/vnet/bfd/bfd_udp.c b/src/vnet/bfd/bfd_udp.c index 1b3c20b852d..dfd030aeccb 100644 --- a/src/vnet/bfd/bfd_udp.c +++ b/src/vnet/bfd/bfd_udp.c @@ -35,78 +35,82 @@ void bfd_add_udp4_transport (vlib_main_t * vm, vlib_buffer_t * b, bfd_udp_session_t * bus) { - udp_header_t *udp; const bfd_udp_key_t *key = &bus->key; b->flags |= VNET_BUFFER_LOCALLY_ORIGINATED; vnet_buffer (b)->ip.adj_index[VLIB_RX] = bus->adj_index; vnet_buffer (b)->ip.adj_index[VLIB_TX] = bus->adj_index; - ip4_header_t *ip4; - const size_t headers_size = sizeof (*ip4) + sizeof (*udp); - vlib_buffer_advance (b, -headers_size); - ip4 = vlib_buffer_get_current (b); - udp = (udp_header_t *) (ip4 + 1); - memset (ip4, 0, headers_size); - ip4->ip_version_and_header_length = 0x45; - ip4->ttl = 255; - ip4->protocol = IP_PROTOCOL_UDP; - ip4->src_address.as_u32 = key->local_addr.ip4.as_u32; - ip4->dst_address.as_u32 = key->peer_addr.ip4.as_u32; - - udp->src_port = clib_host_to_net_u16 (50000); /* FIXME */ - udp->dst_port = clib_host_to_net_u16 (UDP_DST_PORT_bfd4); + typedef struct + { + ip4_header_t ip4; + udp_header_t udp; + } ip4_udp_headers; + ip4_udp_headers *headers = vlib_buffer_get_current (b); + vlib_buffer_advance (b, -sizeof (*headers)); + headers = vlib_buffer_get_current (b); + memset (headers, 0, sizeof (*headers)); + headers->ip4.ip_version_and_header_length = 0x45; + headers->ip4.ttl = 255; + headers->ip4.protocol = IP_PROTOCOL_UDP; + headers->ip4.src_address.as_u32 = key->local_addr.ip4.as_u32; + headers->ip4.dst_address.as_u32 = key->peer_addr.ip4.as_u32; + + headers->udp.src_port = clib_host_to_net_u16 (50000); /* FIXME */ + headers->udp.dst_port = clib_host_to_net_u16 (UDP_DST_PORT_bfd4); /* fix ip length, checksum and udp length */ const u16 ip_length = vlib_buffer_length_in_chain (vm, b); - ip4->length = clib_host_to_net_u16 (ip_length); - ip4->checksum = ip4_header_checksum (ip4); + headers->ip4.length = clib_host_to_net_u16 (ip_length); + headers->ip4.checksum = ip4_header_checksum (&headers->ip4); - const u16 udp_length = ip_length - (sizeof (*ip4)); - udp->length = clib_host_to_net_u16 (udp_length); + const u16 udp_length = ip_length - (sizeof (headers->ip4)); + headers->udp.length = clib_host_to_net_u16 (udp_length); } void bfd_add_udp6_transport (vlib_main_t * vm, vlib_buffer_t * b, bfd_udp_session_t * bus) { - udp_header_t *udp; const bfd_udp_key_t *key = &bus->key; b->flags |= VNET_BUFFER_LOCALLY_ORIGINATED; vnet_buffer (b)->ip.adj_index[VLIB_RX] = bus->adj_index; vnet_buffer (b)->ip.adj_index[VLIB_TX] = bus->adj_index; - ip6_header_t *ip6; - const size_t headers_size = sizeof (*ip6) + sizeof (*udp); - vlib_buffer_advance (b, -headers_size); - ip6 = vlib_buffer_get_current (b); - udp = (udp_header_t *) (ip6 + 1); - memset (ip6, 0, headers_size); - ip6->ip_version_traffic_class_and_flow_label = + typedef struct + { + ip6_header_t ip6; + udp_header_t udp; + } ip6_udp_headers; + vlib_buffer_advance (b, -sizeof (ip6_udp_headers)); + ip6_udp_headers *headers = vlib_buffer_get_current (b); + memset (headers, 0, sizeof (*headers)); + headers->ip6.ip_version_traffic_class_and_flow_label = clib_host_to_net_u32 (0x6 << 28); - ip6->hop_limit = 255; - ip6->protocol = IP_PROTOCOL_UDP; - clib_memcpy (&ip6->src_address, &key->local_addr.ip6, - sizeof (ip6->src_address)); - clib_memcpy (&ip6->dst_address, &key->peer_addr.ip6, - sizeof (ip6->dst_address)); + headers->ip6.hop_limit = 255; + headers->ip6.protocol = IP_PROTOCOL_UDP; + clib_memcpy (&headers->ip6.src_address, &key->local_addr.ip6, + sizeof (headers->ip6.src_address)); + clib_memcpy (&headers->ip6.dst_address, &key->peer_addr.ip6, + sizeof (headers->ip6.dst_address)); - udp->src_port = clib_host_to_net_u16 (50000); /* FIXME */ - udp->dst_port = clib_host_to_net_u16 (UDP_DST_PORT_bfd6); + headers->udp.src_port = clib_host_to_net_u16 (50000); /* FIXME */ + headers->udp.dst_port = clib_host_to_net_u16 (UDP_DST_PORT_bfd6); /* fix ip payload length and udp length */ const u16 udp_length = - vlib_buffer_length_in_chain (vm, b) - (sizeof (*ip6)); - udp->length = clib_host_to_net_u16 (udp_length); - ip6->payload_length = udp->length; + vlib_buffer_length_in_chain (vm, b) - (sizeof (headers->ip6)); + headers->udp.length = clib_host_to_net_u16 (udp_length); + headers->ip6.payload_length = headers->udp.length; /* IPv6 UDP checksum is mandatory */ int bogus = 0; - udp->checksum = ip6_tcp_udp_icmp_compute_checksum (vm, b, ip6, &bogus); + headers->udp.checksum = + ip6_tcp_udp_icmp_compute_checksum (vm, b, &headers->ip6, &bogus); ASSERT (bogus == 0); - if (udp->checksum == 0) + if (headers->udp.checksum == 0) { - udp->checksum = 0xffff; + headers->udp.checksum = 0xffff; } } @@ -237,7 +241,7 @@ bfd_udp_validate_api_input (u32 sw_if_index, ip6_address_t *x = ip_interface_address_get_address (&im->lookup_main, ia); if (local_addr->ip6.as_u64[0] == x->as_u64[0] && - local_addr->ip6.as_u64[1] == x->as_u64[1]) + local_addr->ip6.as_u64[1] == x->as_u64[1]) { /* valid address for this interface */ local_ip_valid = 1; @@ -522,6 +526,15 @@ bfd_udp6_find_headers (vlib_buffer_t * b, const ip6_header_t ** ip6, *udp = NULL; return; } + /* FIXME skip extra headers when searching for UDP ? */ + if ((*ip6)->protocol != IP_PROTOCOL_UDP) + { + BFD_ERR ("Unexpected protocol in IPv6 header '%u', expected '%u' (== " + "IP_PROTOCOL_UDP)" (*ip6)->protocol, IP_PROTOCOL_UDP); + *ip6 = NULL; + *udp = NULL; + return; + } *udp = (udp_header_t *) ((*ip6) + 1); } @@ -604,9 +617,8 @@ bfd_udp6_scan (vlib_main_t * vm, vlib_node_runtime_t * rt, key.peer_addr.ip6.as_u64[0] = ip6->src_address.as_u64[0]; key.peer_addr.ip6.as_u64[1] = ip6->src_address.as_u64[1]; BFD_DBG ("Looking up BFD session using key (sw_if_index=%u, local=%U, " - "peer=%U)", - key.sw_if_index, format_ip6_address, &key.local_addr, - format_ip6_address, &key.peer_addr); + "peer=%U)", key.sw_if_index, format_ip6_address, + &key.local_addr, format_ip6_address, &key.peer_addr); bs = bfd_lookup_session (&bfd_udp_main, &key); } if (!bs) @@ -679,9 +691,11 @@ bfd_udp_input (vlib_main_t * vm, vlib_node_runtime_t * rt, next0 = BFD_UDP_INPUT_NEXT_NORMAL; if (BFD_UDP_ERROR_NONE == error0) { - /* if everything went fine, check for poll bit, if present, re-use - the buffer and based on (now updated) session parameters, send the - final packet back */ + /* + * if everything went fine, check for poll bit, if present, re-use + * the buffer and based on (now updated) session parameters, send + * the final packet back + */ const bfd_pkt_t *pkt = vlib_buffer_get_current (b0); if (bfd_pkt_get_poll (pkt)) { -- cgit 1.2.3-korg