Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

erspan: Initialize options_len before referencing options.

The struct ip_tunnel_info has a flexible array member named
options that is protected by a counted_by(options_len)
attribute.

The compiler will use this information to enforce runtime bounds
checking deployed by FORTIFY_SOURCE string helpers.

As laid out in the GCC documentation, the counter must be
initialized before the first reference to the flexible array
member.

After scanning through the files that use struct ip_tunnel_info
and also refer to options or options_len, it appears the normal
case is to use the ip_tunnel_info_opts_set() helper.

Said helper would initialize options_len properly before copying
data into options, however in the GRE ERSPAN code a partial
update is done, preventing the use of the helper function.

Before this change the handling of ERSPAN traffic in GRE tunnels
would cause a kernel panic when the kernel is compiled with
GCC 15+ and having FORTIFY_SOURCE configured:

memcpy: detected buffer overflow: 4 byte write of buffer size 0

Call Trace:
<IRQ>
__fortify_panic+0xd/0xf
erspan_rcv.cold+0x68/0x83
? ip_route_input_slow+0x816/0x9d0
gre_rcv+0x1b2/0x1c0
gre_rcv+0x8e/0x100
? raw_v4_input+0x2a0/0x2b0
ip_protocol_deliver_rcu+0x1ea/0x210
ip_local_deliver_finish+0x86/0x110
ip_local_deliver+0x65/0x110
? ip_rcv_finish_core+0xd6/0x360
ip_rcv+0x186/0x1a0

Cc: stable@vger.kernel.org
Link: https://gcc.gnu.org/onlinedocs/gcc/Common-Variable-Attributes.html#index-counted_005fby-variable-attribute
Reported-at: https://launchpad.net/bugs/2129580
Fixes: bb5e62f2d547 ("net: Add options as a flexible array to struct ip_tunnel_info")
Signed-off-by: Frode Nordahl <fnordahl@ubuntu.com>
Reviewed-by: Simon Horman <horms@kernel.org>
Link: https://patch.msgid.link/20251213101338.4693-1-fnordahl@ubuntu.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>

authored by

Frode Nordahl and committed by
Paolo Abeni
35ddf66c 350719c3

+8 -4
+4 -2
net/ipv4/ip_gre.c
··· 330 330 if (!tun_dst) 331 331 return PACKET_REJECT; 332 332 333 + /* MUST set options_len before referencing options */ 334 + info = &tun_dst->u.tun_info; 335 + info->options_len = sizeof(*md); 336 + 333 337 /* skb can be uncloned in __iptunnel_pull_header, so 334 338 * old pkt_md is no longer valid and we need to reset 335 339 * it ··· 348 344 memcpy(md2, pkt_md, ver == 1 ? ERSPAN_V1_MDSIZE : 349 345 ERSPAN_V2_MDSIZE); 350 346 351 - info = &tun_dst->u.tun_info; 352 347 __set_bit(IP_TUNNEL_ERSPAN_OPT_BIT, 353 348 info->key.tun_flags); 354 - info->options_len = sizeof(*md); 355 349 } 356 350 357 351 skb_reset_mac_header(skb);
+4 -2
net/ipv6/ip6_gre.c
··· 535 535 if (!tun_dst) 536 536 return PACKET_REJECT; 537 537 538 + /* MUST set options_len before referencing options */ 539 + info = &tun_dst->u.tun_info; 540 + info->options_len = sizeof(*md); 541 + 538 542 /* skb can be uncloned in __iptunnel_pull_header, so 539 543 * old pkt_md is no longer valid and we need to reset 540 544 * it ··· 547 543 skb_network_header_len(skb); 548 544 pkt_md = (struct erspan_metadata *)(gh + gre_hdr_len + 549 545 sizeof(*ershdr)); 550 - info = &tun_dst->u.tun_info; 551 546 md = ip_tunnel_info_opts(info); 552 547 md->version = ver; 553 548 md2 = &md->u.md2; ··· 554 551 ERSPAN_V2_MDSIZE); 555 552 __set_bit(IP_TUNNEL_ERSPAN_OPT_BIT, 556 553 info->key.tun_flags); 557 - info->options_len = sizeof(*md); 558 554 559 555 ip6_tnl_rcv(tunnel, skb, tpi, tun_dst, log_ecn_error); 560 556