From 03092c1982468ff6ffe260b0215f910d4c486b04 Mon Sep 17 00:00:00 2001 From: Ole Troan Date: Tue, 23 Nov 2021 15:55:39 +0100 Subject: ip: extension header parsing fails for fragment header Refactor and improve boundary checking on IPv6 extension header handling. Limit parsing of IPv6 extension headers to a maximum of 4 headers and a depth of 256 bytes. Type: fix Signed-off-by: Ole Troan Change-Id: Ide40aaa2b482ceef7e92f02fa0caeadb3b8f7556 Signed-off-by: Ole Troan --- src/vnet/ip/ip6_to_ip4.h | 54 +++++++++++++++++------------------------------- 1 file changed, 19 insertions(+), 35 deletions(-) (limited to 'src/vnet/ip/ip6_to_ip4.h') diff --git a/src/vnet/ip/ip6_to_ip4.h b/src/vnet/ip/ip6_to_ip4.h index 6a533e3b54e..b1b5bdb2d11 100644 --- a/src/vnet/ip/ip6_to_ip4.h +++ b/src/vnet/ip/ip6_to_ip4.h @@ -62,41 +62,25 @@ static u8 icmp6_to_icmp_updater_pointer_table[] = * @returns 0 on success, non-zero value otherwise. */ static_always_inline int -ip6_parse (vlib_main_t * vm, vlib_buffer_t * b, const ip6_header_t * ip6, - u32 buff_len, u8 * l4_protocol, u16 * l4_offset, - u16 * frag_hdr_offset) +ip6_parse (vlib_main_t *vm, vlib_buffer_t *b, ip6_header_t *ip6, u32 buff_len, + u8 *l4_protocol, u16 *l4_offset, u16 *frag_hdr_offset) { - ip6_ext_header_t *last_hdr, *frag_hdr; - u32 length; - if (ip6_walk_ext_hdr - (vm, b, ip6, IP_PROTOCOL_IPV6_FRAGMENTATION, &length, &frag_hdr, - &last_hdr)) + ip6_ext_hdr_chain_t hdr_chain; + int res = + ip6_ext_header_walk (b, ip6, IP_PROTOCOL_IPV6_FRAGMENTATION, &hdr_chain); + if (res < 0) { return -1; } - - if (length > 0) - { - if (frag_hdr) - { - *frag_hdr_offset = (u8 *) frag_hdr - (u8 *) ip6; - } - else - { - *frag_hdr_offset = 0; - } - *l4_protocol = last_hdr->next_hdr; - } + if (hdr_chain.eh[res].protocol == IP_PROTOCOL_IPV6_FRAGMENTATION) + *frag_hdr_offset = hdr_chain.eh[res].offset; else - { - *frag_hdr_offset = 0; - *l4_protocol = ip6->protocol; - } - *l4_offset = sizeof (*ip6) + length; + *frag_hdr_offset = 0; - return (buff_len < (*l4_offset + 4)) || - (clib_net_to_host_u16 (ip6->payload_length) < - (*l4_offset + 4 - sizeof (*ip6))); + *l4_protocol = hdr_chain.eh[hdr_chain.length - 1].protocol; + *l4_offset = hdr_chain.eh[hdr_chain.length - 1].offset; + + return 0; } /** @@ -124,13 +108,13 @@ ip6_get_port (vlib_main_t * vm, vlib_buffer_t * b, ip6_header_t * ip6, u16 frag_offset; u8 *l4; - if (ip6_parse - (vm, b, ip6, buffer_len, &l4_protocol, &l4_offset, &frag_offset)) - return 0; - + if (ip6_parse (vm, b, ip6, buffer_len, &l4_protocol, &l4_offset, + &frag_offset)) + { + return 0; + } if (frag_offset && - ip6_frag_hdr_offset (((ip6_frag_hdr_t *) - u8_ptr_add (ip6, frag_offset)))) + ip6_frag_hdr_offset (((ip6_frag_hdr_t *) u8_ptr_add (ip6, frag_offset)))) return 0; //Can't deal with non-first fragment for now if (ip_protocol) -- cgit 1.2.3-korg