From: Klement Sekera Date: Wed, 3 Nov 2021 16:57:28 +0000 (+0100) Subject: ip: reassembly: avoid reading truncated L4 headers X-Git-Tag: v22.06-rc0~307 X-Git-Url: https://gerrit.fd.io/r/gitweb?a=commitdiff_plain;h=5a58e7c546239da5c500611d60cf4e7635f138c5;p=vpp.git ip: reassembly: avoid reading truncated L4 headers Check if L4 headers are truncated and if so, set a flag for (future) consumers instead of reading/writing garbage data. Type: fix Fixes: de34c35fc73226943538149fae9dbc5cfbdc6e75 Change-Id: I0b656ec103a11c356b98a6f36cad98536a78d1dc Signed-off-by: Klement Sekera --- diff --git a/src/vnet/buffer.h b/src/vnet/buffer.h index 09abedd5e74..594c6083b84 100644 --- a/src/vnet/buffer.h +++ b/src/vnet/buffer.h @@ -244,7 +244,8 @@ typedef struct u8 save_rewrite_length; u8 ip_proto; /* protocol in ip header */ u8 icmp_type_or_tcp_flags; - u8 is_non_first_fragment; + u8 is_non_first_fragment : 1; + u8 l4_layer_truncated : 7; u32 tcp_seq_number; }; /* full reassembly output variables */ diff --git a/src/vnet/ip/reass/ip4_sv_reass.c b/src/vnet/ip/reass/ip4_sv_reass.c index cd5e19b65d3..31177809f7b 100644 --- a/src/vnet/ip/reass/ip4_sv_reass.c +++ b/src/vnet/ip/reass/ip4_sv_reass.c @@ -48,7 +48,7 @@ typedef struct { struct { - u32 xx_id; + u32 fib_index; ip4_address_t src; ip4_address_t dst; u16 frag_id; @@ -189,6 +189,7 @@ typedef struct u8 ip_proto; u16 l4_src_port; u16 l4_dst_port; + int l4_layer_truncated; } ip4_sv_reass_trace_t; extern vlib_node_registration_t ip4_sv_reass_node; @@ -225,6 +226,10 @@ format_ip4_sv_reass_trace (u8 * s, va_list * args) s = format (s, "[not-fragmented]"); break; } + if (t->l4_layer_truncated) + { + s = format (s, " [l4-layer-truncated]"); + } return s; } @@ -232,7 +237,8 @@ static void ip4_sv_reass_add_trace (vlib_main_t *vm, vlib_node_runtime_t *node, ip4_sv_reass_t *reass, u32 bi, ip4_sv_reass_trace_operation_e action, u32 ip_proto, - u16 l4_src_port, u16 l4_dst_port) + u16 l4_src_port, u16 l4_dst_port, + int l4_layer_truncated) { vlib_buffer_t *b = vlib_get_buffer (vm, bi); if (pool_is_free_index @@ -253,6 +259,7 @@ ip4_sv_reass_add_trace (vlib_main_t *vm, vlib_node_runtime_t *node, t->ip_proto = ip_proto; t->l4_src_port = l4_src_port; t->l4_dst_port = l4_dst_port; + t->l4_layer_truncated = l4_layer_truncated; #if 0 static u8 *s = NULL; s = format (s, "%U", format_ip4_sv_reass_trace, NULL, NULL, t); @@ -407,9 +414,10 @@ ip4_sv_reass_update (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_buffer_t *b0 = vlib_get_buffer (vm, bi0); if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED)) { - ip4_sv_reass_add_trace (vm, node, reass, bi0, REASS_FINISH, - reass->ip_proto, reass->l4_src_port, - reass->l4_dst_port); + ip4_sv_reass_add_trace ( + vm, node, reass, bi0, REASS_FINISH, reass->ip_proto, + reass->l4_src_port, reass->l4_dst_port, + vnet_buffer (b0)->ip.reass.l4_layer_truncated); } } vec_add1 (reass->cached_buffers, bi0); @@ -417,8 +425,9 @@ ip4_sv_reass_update (vlib_main_t *vm, vlib_node_runtime_t *node, { if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED)) { - ip4_sv_reass_add_trace (vm, node, reass, bi0, REASS_FRAGMENT_CACHE, - ~0, ~0, ~0); + ip4_sv_reass_add_trace ( + vm, node, reass, bi0, REASS_FRAGMENT_CACHE, ~0, ~0, ~0, + vnet_buffer (b0)->ip.reass.l4_layer_truncated); } if (vec_len (reass->cached_buffers) > rm->max_reass_len) { @@ -428,6 +437,19 @@ ip4_sv_reass_update (vlib_main_t *vm, vlib_node_runtime_t *node, return rc; } +always_inline int +l4_layer_truncated (ip4_header_t *ip) +{ + static const int l4_layer_length[256] = { + [IP_PROTOCOL_TCP] = sizeof (tcp_header_t), + [IP_PROTOCOL_UDP] = sizeof (udp_header_t), + [IP_PROTOCOL_ICMP] = sizeof (icmp46_header_t), + }; + + return ((u8 *) ip + ip4_header_bytes (ip) + l4_layer_length[ip->protocol] > + (u8 *) ip + clib_net_to_host_u16 (ip->length)); +} + always_inline uword ip4_sv_reass_inline (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame, bool is_feature, @@ -482,6 +504,7 @@ ip4_sv_reass_inline (vlib_main_t * vm, vlib_node_runtime_t * node, (is_output_feature ? 1 : 0) * vnet_buffer (b1)-> ip.save_rewrite_length); + if (PREDICT_FALSE (ip4_get_fragment_more (ip0) || ip4_get_fragment_offset (ip0)) || (ip4_get_fragment_more (ip1) || ip4_get_fragment_offset (ip1))) @@ -506,29 +529,40 @@ ip4_sv_reass_inline (vlib_main_t * vm, vlib_node_runtime_t * node, } vnet_buffer (b0)->ip.reass.is_non_first_fragment = 0; vnet_buffer (b0)->ip.reass.ip_proto = ip0->protocol; - if (IP_PROTOCOL_TCP == ip0->protocol) + if (l4_layer_truncated (ip0)) { - vnet_buffer (b0)->ip.reass.icmp_type_or_tcp_flags = - ((tcp_header_t *) (ip0 + 1))->flags; - vnet_buffer (b0)->ip.reass.tcp_ack_number = - ((tcp_header_t *) (ip0 + 1))->ack_number; - vnet_buffer (b0)->ip.reass.tcp_seq_number = - ((tcp_header_t *) (ip0 + 1))->seq_number; + vnet_buffer (b0)->ip.reass.l4_layer_truncated = 1; + vnet_buffer (b0)->ip.reass.l4_src_port = 0; + vnet_buffer (b0)->ip.reass.l4_dst_port = 0; } - else if (IP_PROTOCOL_ICMP == ip0->protocol) + else { - vnet_buffer (b0)->ip.reass.icmp_type_or_tcp_flags = - ((icmp46_header_t *) (ip0 + 1))->type; + vnet_buffer (b0)->ip.reass.l4_layer_truncated = 0; + if (IP_PROTOCOL_TCP == ip0->protocol) + { + vnet_buffer (b0)->ip.reass.icmp_type_or_tcp_flags = + ((tcp_header_t *) (ip0 + 1))->flags; + vnet_buffer (b0)->ip.reass.tcp_ack_number = + ((tcp_header_t *) (ip0 + 1))->ack_number; + vnet_buffer (b0)->ip.reass.tcp_seq_number = + ((tcp_header_t *) (ip0 + 1))->seq_number; + } + else if (IP_PROTOCOL_ICMP == ip0->protocol) + { + vnet_buffer (b0)->ip.reass.icmp_type_or_tcp_flags = + ((icmp46_header_t *) (ip0 + 1))->type; + } + vnet_buffer (b0)->ip.reass.l4_src_port = ip4_get_port (ip0, 1); + vnet_buffer (b0)->ip.reass.l4_dst_port = ip4_get_port (ip0, 0); } - vnet_buffer (b0)->ip.reass.l4_src_port = ip4_get_port (ip0, 1); - vnet_buffer (b0)->ip.reass.l4_dst_port = ip4_get_port (ip0, 0); if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED)) { - ip4_sv_reass_add_trace (vm, node, NULL, from[(b - 2) - bufs], - REASS_PASSTHROUGH, - vnet_buffer (b0)->ip.reass.ip_proto, - vnet_buffer (b0)->ip.reass.l4_src_port, - vnet_buffer (b0)->ip.reass.l4_dst_port); + ip4_sv_reass_add_trace ( + vm, node, NULL, from[(b - 2) - bufs], REASS_PASSTHROUGH, + vnet_buffer (b0)->ip.reass.ip_proto, + vnet_buffer (b0)->ip.reass.l4_src_port, + vnet_buffer (b0)->ip.reass.l4_dst_port, + vnet_buffer (b0)->ip.reass.l4_layer_truncated); } if (is_feature) { @@ -541,29 +575,40 @@ ip4_sv_reass_inline (vlib_main_t * vm, vlib_node_runtime_t * node, } vnet_buffer (b1)->ip.reass.is_non_first_fragment = 0; vnet_buffer (b1)->ip.reass.ip_proto = ip1->protocol; - if (IP_PROTOCOL_TCP == ip1->protocol) + if (l4_layer_truncated (ip1)) { - vnet_buffer (b1)->ip.reass.icmp_type_or_tcp_flags = - ((tcp_header_t *) (ip1 + 1))->flags; - vnet_buffer (b1)->ip.reass.tcp_ack_number = - ((tcp_header_t *) (ip1 + 1))->ack_number; - vnet_buffer (b1)->ip.reass.tcp_seq_number = - ((tcp_header_t *) (ip1 + 1))->seq_number; + vnet_buffer (b1)->ip.reass.l4_layer_truncated = 1; + vnet_buffer (b1)->ip.reass.l4_src_port = 0; + vnet_buffer (b1)->ip.reass.l4_dst_port = 0; } - else if (IP_PROTOCOL_ICMP == ip1->protocol) + else { - vnet_buffer (b1)->ip.reass.icmp_type_or_tcp_flags = - ((icmp46_header_t *) (ip1 + 1))->type; + vnet_buffer (b1)->ip.reass.l4_layer_truncated = 0; + if (IP_PROTOCOL_TCP == ip1->protocol) + { + vnet_buffer (b1)->ip.reass.icmp_type_or_tcp_flags = + ((tcp_header_t *) (ip1 + 1))->flags; + vnet_buffer (b1)->ip.reass.tcp_ack_number = + ((tcp_header_t *) (ip1 + 1))->ack_number; + vnet_buffer (b1)->ip.reass.tcp_seq_number = + ((tcp_header_t *) (ip1 + 1))->seq_number; + } + else if (IP_PROTOCOL_ICMP == ip1->protocol) + { + vnet_buffer (b1)->ip.reass.icmp_type_or_tcp_flags = + ((icmp46_header_t *) (ip1 + 1))->type; + } + vnet_buffer (b1)->ip.reass.l4_src_port = ip4_get_port (ip1, 1); + vnet_buffer (b1)->ip.reass.l4_dst_port = ip4_get_port (ip1, 0); } - vnet_buffer (b1)->ip.reass.l4_src_port = ip4_get_port (ip1, 1); - vnet_buffer (b1)->ip.reass.l4_dst_port = ip4_get_port (ip1, 0); if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED)) { - ip4_sv_reass_add_trace (vm, node, NULL, from[(b - 1) - bufs], - REASS_PASSTHROUGH, - vnet_buffer (b1)->ip.reass.ip_proto, - vnet_buffer (b1)->ip.reass.l4_src_port, - vnet_buffer (b1)->ip.reass.l4_dst_port); + ip4_sv_reass_add_trace ( + vm, node, NULL, from[(b - 1) - bufs], REASS_PASSTHROUGH, + vnet_buffer (b1)->ip.reass.ip_proto, + vnet_buffer (b1)->ip.reass.l4_src_port, + vnet_buffer (b1)->ip.reass.l4_dst_port, + vnet_buffer (b1)->ip.reass.l4_layer_truncated); } n_left_from -= 2; @@ -608,29 +653,38 @@ ip4_sv_reass_inline (vlib_main_t * vm, vlib_node_runtime_t * node, } vnet_buffer (b0)->ip.reass.is_non_first_fragment = 0; vnet_buffer (b0)->ip.reass.ip_proto = ip0->protocol; - if (IP_PROTOCOL_TCP == ip0->protocol) + if (l4_layer_truncated (ip0)) { - vnet_buffer (b0)->ip.reass.icmp_type_or_tcp_flags = - ((tcp_header_t *) (ip0 + 1))->flags; - vnet_buffer (b0)->ip.reass.tcp_ack_number = - ((tcp_header_t *) (ip0 + 1))->ack_number; - vnet_buffer (b0)->ip.reass.tcp_seq_number = - ((tcp_header_t *) (ip0 + 1))->seq_number; + vnet_buffer (b0)->ip.reass.l4_layer_truncated = 1; } - else if (IP_PROTOCOL_ICMP == ip0->protocol) + else { - vnet_buffer (b0)->ip.reass.icmp_type_or_tcp_flags = - ((icmp46_header_t *) (ip0 + 1))->type; + vnet_buffer (b0)->ip.reass.l4_layer_truncated = 0; + if (IP_PROTOCOL_TCP == ip0->protocol) + { + vnet_buffer (b0)->ip.reass.icmp_type_or_tcp_flags = + ((tcp_header_t *) (ip0 + 1))->flags; + vnet_buffer (b0)->ip.reass.tcp_ack_number = + ((tcp_header_t *) (ip0 + 1))->ack_number; + vnet_buffer (b0)->ip.reass.tcp_seq_number = + ((tcp_header_t *) (ip0 + 1))->seq_number; + } + else if (IP_PROTOCOL_ICMP == ip0->protocol) + { + vnet_buffer (b0)->ip.reass.icmp_type_or_tcp_flags = + ((icmp46_header_t *) (ip0 + 1))->type; + } + vnet_buffer (b0)->ip.reass.l4_src_port = ip4_get_port (ip0, 1); + vnet_buffer (b0)->ip.reass.l4_dst_port = ip4_get_port (ip0, 0); } - vnet_buffer (b0)->ip.reass.l4_src_port = ip4_get_port (ip0, 1); - vnet_buffer (b0)->ip.reass.l4_dst_port = ip4_get_port (ip0, 0); if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED)) { - ip4_sv_reass_add_trace (vm, node, NULL, from[(b - 1) - bufs], - REASS_PASSTHROUGH, - vnet_buffer (b0)->ip.reass.ip_proto, - vnet_buffer (b0)->ip.reass.l4_src_port, - vnet_buffer (b0)->ip.reass.l4_dst_port); + ip4_sv_reass_add_trace ( + vm, node, NULL, from[(b - 1) - bufs], REASS_PASSTHROUGH, + vnet_buffer (b0)->ip.reass.ip_proto, + vnet_buffer (b0)->ip.reass.l4_src_port, + vnet_buffer (b0)->ip.reass.l4_dst_port, + vnet_buffer (b0)->ip.reass.l4_layer_truncated); } n_left_from -= 1; @@ -679,29 +733,42 @@ slow_path: } vnet_buffer (b0)->ip.reass.is_non_first_fragment = 0; vnet_buffer (b0)->ip.reass.ip_proto = ip0->protocol; - if (IP_PROTOCOL_TCP == ip0->protocol) + if (l4_layer_truncated (ip0)) { - vnet_buffer (b0)->ip.reass.icmp_type_or_tcp_flags = - ((tcp_header_t *) (ip0 + 1))->flags; - vnet_buffer (b0)->ip.reass.tcp_ack_number = - ((tcp_header_t *) (ip0 + 1))->ack_number; - vnet_buffer (b0)->ip.reass.tcp_seq_number = - ((tcp_header_t *) (ip0 + 1))->seq_number; + vnet_buffer (b0)->ip.reass.l4_layer_truncated = 1; + vnet_buffer (b0)->ip.reass.l4_src_port = 0; + vnet_buffer (b0)->ip.reass.l4_dst_port = 0; } - else if (IP_PROTOCOL_ICMP == ip0->protocol) + else { - vnet_buffer (b0)->ip.reass.icmp_type_or_tcp_flags = - ((icmp46_header_t *) (ip0 + 1))->type; + vnet_buffer (b0)->ip.reass.l4_layer_truncated = 0; + if (IP_PROTOCOL_TCP == ip0->protocol) + { + vnet_buffer (b0)->ip.reass.icmp_type_or_tcp_flags = + ((tcp_header_t *) (ip0 + 1))->flags; + vnet_buffer (b0)->ip.reass.tcp_ack_number = + ((tcp_header_t *) (ip0 + 1))->ack_number; + vnet_buffer (b0)->ip.reass.tcp_seq_number = + ((tcp_header_t *) (ip0 + 1))->seq_number; + } + else if (IP_PROTOCOL_ICMP == ip0->protocol) + { + vnet_buffer (b0)->ip.reass.icmp_type_or_tcp_flags = + ((icmp46_header_t *) (ip0 + 1))->type; + } + vnet_buffer (b0)->ip.reass.l4_src_port = + ip4_get_port (ip0, 1); + vnet_buffer (b0)->ip.reass.l4_dst_port = + ip4_get_port (ip0, 0); } - vnet_buffer (b0)->ip.reass.l4_src_port = ip4_get_port (ip0, 1); - vnet_buffer (b0)->ip.reass.l4_dst_port = ip4_get_port (ip0, 0); if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED)) { ip4_sv_reass_add_trace ( vm, node, NULL, bi0, REASS_PASSTHROUGH, vnet_buffer (b0)->ip.reass.ip_proto, vnet_buffer (b0)->ip.reass.l4_src_port, - vnet_buffer (b0)->ip.reass.l4_dst_port); + vnet_buffer (b0)->ip.reass.l4_dst_port, + vnet_buffer (b0)->ip.reass.l4_layer_truncated); } goto packet_enqueue; } @@ -771,7 +838,8 @@ slow_path: { ip4_sv_reass_add_trace ( vm, node, reass, bi0, REASS_FRAGMENT_FORWARD, - reass->ip_proto, reass->l4_src_port, reass->l4_dst_port); + reass->ip_proto, reass->l4_src_port, reass->l4_dst_port, + vnet_buffer (b0)->ip.reass.l4_layer_truncated); } goto packet_enqueue; } @@ -843,7 +911,8 @@ slow_path: { ip4_sv_reass_add_trace ( vm, node, reass, bi0, REASS_FRAGMENT_FORWARD, - reass->ip_proto, reass->l4_src_port, reass->l4_dst_port); + reass->ip_proto, reass->l4_src_port, reass->l4_dst_port, + vnet_buffer (b0)->ip.reass.l4_layer_truncated); } vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next, n_left_to_next, bi0, @@ -1252,9 +1321,8 @@ format_ip4_sv_reass_key (u8 * s, va_list * args) { ip4_sv_reass_key_t *key = va_arg (*args, ip4_sv_reass_key_t *); s = - format (s, - "xx_id: %u, src: %U, dst: %U, frag_id: %u, proto: %u", - key->xx_id, format_ip4_address, &key->src, format_ip4_address, + format (s, "fib_index: %u, src: %U, dst: %U, frag_id: %u, proto: %u", + key->fib_index, format_ip4_address, &key->src, format_ip4_address, &key->dst, clib_net_to_host_u16 (key->frag_id), key->proto); return s; } diff --git a/src/vnet/ip/reass/ip6_sv_reass.c b/src/vnet/ip/reass/ip6_sv_reass.c index 28941311f50..a2dcfedf311 100644 --- a/src/vnet/ip/reass/ip6_sv_reass.c +++ b/src/vnet/ip/reass/ip6_sv_reass.c @@ -50,7 +50,7 @@ typedef struct { ip6_address_t src; ip6_address_t dst; - u32 xx_id; + u32 fib_index; u32 frag_id; u8 unused[7]; u8 proto; @@ -1057,9 +1057,10 @@ static u8 * format_ip6_sv_reass_key (u8 * s, va_list * args) { ip6_sv_reass_key_t *key = va_arg (*args, ip6_sv_reass_key_t *); - s = format (s, "xx_id: %u, src: %U, dst: %U, frag_id: %u, proto: %u", - key->xx_id, format_ip6_address, &key->src, format_ip6_address, - &key->dst, clib_net_to_host_u16 (key->frag_id), key->proto); + s = + format (s, "fib_index: %u, src: %U, dst: %U, frag_id: %u, proto: %u", + key->fib_index, format_ip6_address, &key->src, format_ip6_address, + &key->dst, clib_net_to_host_u16 (key->frag_id), key->proto); return s; }