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.

net: add xmit recursion limit to tunnel xmit functions

Tunnel xmit functions (iptunnel_xmit, ip6tunnel_xmit) lack their own
recursion limit. When a bond device in broadcast mode has GRE tap
interfaces as slaves, and those GRE tunnels route back through the
bond, multicast/broadcast traffic triggers infinite recursion between
bond_xmit_broadcast() and ip_tunnel_xmit()/ip6_tnl_xmit(), causing
kernel stack overflow.

The existing XMIT_RECURSION_LIMIT (8) in the no-qdisc path is not
sufficient because tunnel recursion involves route lookups and full IP
output, consuming much more stack per level. Use a lower limit of 4
(IP_TUNNEL_RECURSION_LIMIT) to prevent overflow.

Add recursion detection using dev_xmit_recursion helpers directly in
iptunnel_xmit() and ip6tunnel_xmit() to cover all IPv4/IPv6 tunnel
paths including UDP encapsulated tunnels (VXLAN, Geneve, etc.).

Move dev_xmit_recursion helpers from net/core/dev.h to public header
include/linux/netdevice.h so they can be used by tunnel code.

BUG: KASAN: stack-out-of-bounds in blake2s.constprop.0+0xe7/0x160
Write of size 32 at addr ffff88810033fed0 by task kworker/0:1/11
Workqueue: mld mld_ifc_work
Call Trace:
<TASK>
__build_flow_key.constprop.0 (net/ipv4/route.c:515)
ip_rt_update_pmtu (net/ipv4/route.c:1073)
iptunnel_xmit (net/ipv4/ip_tunnel_core.c:84)
ip_tunnel_xmit (net/ipv4/ip_tunnel.c:847)
gre_tap_xmit (net/ipv4/ip_gre.c:779)
dev_hard_start_xmit (net/core/dev.c:3887)
sch_direct_xmit (net/sched/sch_generic.c:347)
__dev_queue_xmit (net/core/dev.c:4802)
bond_dev_queue_xmit (drivers/net/bonding/bond_main.c:312)
bond_xmit_broadcast (drivers/net/bonding/bond_main.c:5279)
bond_start_xmit (drivers/net/bonding/bond_main.c:5530)
dev_hard_start_xmit (net/core/dev.c:3887)
__dev_queue_xmit (net/core/dev.c:4841)
ip_finish_output2 (net/ipv4/ip_output.c:237)
ip_output (net/ipv4/ip_output.c:438)
iptunnel_xmit (net/ipv4/ip_tunnel_core.c:86)
gre_tap_xmit (net/ipv4/ip_gre.c:779)
dev_hard_start_xmit (net/core/dev.c:3887)
sch_direct_xmit (net/sched/sch_generic.c:347)
__dev_queue_xmit (net/core/dev.c:4802)
bond_dev_queue_xmit (drivers/net/bonding/bond_main.c:312)
bond_xmit_broadcast (drivers/net/bonding/bond_main.c:5279)
bond_start_xmit (drivers/net/bonding/bond_main.c:5530)
dev_hard_start_xmit (net/core/dev.c:3887)
__dev_queue_xmit (net/core/dev.c:4841)
ip_finish_output2 (net/ipv4/ip_output.c:237)
ip_output (net/ipv4/ip_output.c:438)
iptunnel_xmit (net/ipv4/ip_tunnel_core.c:86)
ip_tunnel_xmit (net/ipv4/ip_tunnel.c:847)
gre_tap_xmit (net/ipv4/ip_gre.c:779)
dev_hard_start_xmit (net/core/dev.c:3887)
sch_direct_xmit (net/sched/sch_generic.c:347)
__dev_queue_xmit (net/core/dev.c:4802)
bond_dev_queue_xmit (drivers/net/bonding/bond_main.c:312)
bond_xmit_broadcast (drivers/net/bonding/bond_main.c:5279)
bond_start_xmit (drivers/net/bonding/bond_main.c:5530)
dev_hard_start_xmit (net/core/dev.c:3887)
__dev_queue_xmit (net/core/dev.c:4841)
mld_sendpack
mld_ifc_work
process_one_work
worker_thread
</TASK>

Fixes: 745e20f1b626 ("net: add a recursion limit in xmit path")
Reported-by: Xiang Mei <xmei5@asu.edu>
Signed-off-by: Weiming Shi <bestswngs@gmail.com>
Link: https://patch.msgid.link/20260306160133.3852900-2-bestswngs@gmail.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>

authored by

Weiming Shi and committed by
Paolo Abeni
6f1a9140 32288358

+64 -35
+32
include/linux/netdevice.h
··· 3576 3576 }; 3577 3577 DECLARE_PER_CPU(struct page_pool_bh, system_page_pool); 3578 3578 3579 + #define XMIT_RECURSION_LIMIT 8 3580 + 3579 3581 #ifndef CONFIG_PREEMPT_RT 3580 3582 static inline int dev_recursion_level(void) 3581 3583 { 3582 3584 return this_cpu_read(softnet_data.xmit.recursion); 3585 + } 3586 + 3587 + static inline bool dev_xmit_recursion(void) 3588 + { 3589 + return unlikely(__this_cpu_read(softnet_data.xmit.recursion) > 3590 + XMIT_RECURSION_LIMIT); 3591 + } 3592 + 3593 + static inline void dev_xmit_recursion_inc(void) 3594 + { 3595 + __this_cpu_inc(softnet_data.xmit.recursion); 3596 + } 3597 + 3598 + static inline void dev_xmit_recursion_dec(void) 3599 + { 3600 + __this_cpu_dec(softnet_data.xmit.recursion); 3583 3601 } 3584 3602 #else 3585 3603 static inline int dev_recursion_level(void) ··· 3605 3587 return current->net_xmit.recursion; 3606 3588 } 3607 3589 3590 + static inline bool dev_xmit_recursion(void) 3591 + { 3592 + return unlikely(current->net_xmit.recursion > XMIT_RECURSION_LIMIT); 3593 + } 3594 + 3595 + static inline void dev_xmit_recursion_inc(void) 3596 + { 3597 + current->net_xmit.recursion++; 3598 + } 3599 + 3600 + static inline void dev_xmit_recursion_dec(void) 3601 + { 3602 + current->net_xmit.recursion--; 3603 + } 3608 3604 #endif 3609 3605 3610 3606 void __netif_schedule(struct Qdisc *q);
+12
include/net/ip6_tunnel.h
··· 156 156 { 157 157 int pkt_len, err; 158 158 159 + if (dev_recursion_level() > IP_TUNNEL_RECURSION_LIMIT) { 160 + net_crit_ratelimited("Dead loop on virtual device %s, fix it urgently!\n", 161 + dev->name); 162 + DEV_STATS_INC(dev, tx_errors); 163 + kfree_skb(skb); 164 + return; 165 + } 166 + 167 + dev_xmit_recursion_inc(); 168 + 159 169 memset(skb->cb, 0, sizeof(struct inet6_skb_parm)); 160 170 IP6CB(skb)->flags = ip6cb_flags; 161 171 pkt_len = skb->len - skb_inner_network_offset(skb); ··· 176 166 pkt_len = -1; 177 167 iptunnel_xmit_stats(dev, pkt_len); 178 168 } 169 + 170 + dev_xmit_recursion_dec(); 179 171 } 180 172 #endif 181 173 #endif
+7
include/net/ip_tunnels.h
··· 27 27 #include <net/ip6_route.h> 28 28 #endif 29 29 30 + /* Recursion limit for tunnel xmit to detect routing loops. 31 + * Unlike XMIT_RECURSION_LIMIT (8) used in the no-qdisc path, tunnel 32 + * recursion involves route lookups and full IP output, consuming much 33 + * more stack per level, so a lower limit is needed. 34 + */ 35 + #define IP_TUNNEL_RECURSION_LIMIT 4 36 + 30 37 /* Keep error state on tunnel for 30 sec */ 31 38 #define IPTUNNEL_ERR_TIMEO (30*HZ) 32 39
-35
net/core/dev.h
··· 366 366 367 367 void kick_defer_list_purge(unsigned int cpu); 368 368 369 - #define XMIT_RECURSION_LIMIT 8 370 - 371 - #ifndef CONFIG_PREEMPT_RT 372 - static inline bool dev_xmit_recursion(void) 373 - { 374 - return unlikely(__this_cpu_read(softnet_data.xmit.recursion) > 375 - XMIT_RECURSION_LIMIT); 376 - } 377 - 378 - static inline void dev_xmit_recursion_inc(void) 379 - { 380 - __this_cpu_inc(softnet_data.xmit.recursion); 381 - } 382 - 383 - static inline void dev_xmit_recursion_dec(void) 384 - { 385 - __this_cpu_dec(softnet_data.xmit.recursion); 386 - } 387 - #else 388 - static inline bool dev_xmit_recursion(void) 389 - { 390 - return unlikely(current->net_xmit.recursion > XMIT_RECURSION_LIMIT); 391 - } 392 - 393 - static inline void dev_xmit_recursion_inc(void) 394 - { 395 - current->net_xmit.recursion++; 396 - } 397 - 398 - static inline void dev_xmit_recursion_dec(void) 399 - { 400 - current->net_xmit.recursion--; 401 - } 402 - #endif 403 - 404 369 int dev_set_hwtstamp_phylib(struct net_device *dev, 405 370 struct kernel_hwtstamp_config *cfg, 406 371 struct netlink_ext_ack *extack);
+13
net/ipv4/ip_tunnel_core.c
··· 58 58 struct iphdr *iph; 59 59 int err; 60 60 61 + if (dev_recursion_level() > IP_TUNNEL_RECURSION_LIMIT) { 62 + net_crit_ratelimited("Dead loop on virtual device %s, fix it urgently!\n", 63 + dev->name); 64 + DEV_STATS_INC(dev, tx_errors); 65 + ip_rt_put(rt); 66 + kfree_skb(skb); 67 + return; 68 + } 69 + 70 + dev_xmit_recursion_inc(); 71 + 61 72 skb_scrub_packet(skb, xnet); 62 73 63 74 skb_clear_hash_if_not_l4(skb); ··· 99 88 pkt_len = 0; 100 89 iptunnel_xmit_stats(dev, pkt_len); 101 90 } 91 + 92 + dev_xmit_recursion_dec(); 102 93 } 103 94 EXPORT_SYMBOL_GPL(iptunnel_xmit); 104 95