From: Chenguang Zhao Commit de2c211868b9 ("ipvs: Always clear ipvs_property flag in skb_scrub_packet()") moved ipvs_reset() before the xnet check, making the call unconditional. The intent was to fix a bpf_redirect case where stale ipvs_property on an skb re-entering the RX path caused the SNAT hook to be skipped. However the change is too broad: when IPVS NAT sits above an ipvlan L3 interface in the same netns, the following loop happens: LOCAL_OUT -> IPVS DNAT (sets ipvs_property=1) -> dst_output -> ipvlan -> skb_scrub_packet() -> ipvs_reset() clears the flag -> ipvlan_process_v4_outbound() -> ip_local_out() -> LOCAL_OUT -> IPVS sees ipvs_property=0, processes again -> infinite recursion syzbot reported this as a stack overflow on a KASAN kernel where each level burns ~3.3 KB of stack and XMIT_RECURSION_LIMIT falls short. On non-KASAN kernels the dead-loop detector catches it and prints "Dead loop on virtual device", but traffic is still broken. Fixes: de2c211868b9 ("ipvs: Always clear ipvs_property flag in skb_scrub_packet()") Reported-by: syzbot+2b120190d9e54ad8c65d@syzkaller.appspotmail.com Closes: https://syzkaller.appspot.com/bug?extid=2b120190d9e54ad8c65d Signed-off-by: Chenguang Zhao --- v2: add Julian into v2. v1: - https://lore.kernel.org/all/20260924063312.1194019-1-chenguang.zhao@linux.dev/ net/core/skbuff.c | 3 +-- net/ipv4/ip_input.c | 1 + net/ipv6/ip6_input.c | 1 + 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/net/core/skbuff.c b/net/core/skbuff.c index cc3b4b70288b..6912ca0d2228 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -6303,11 +6303,10 @@ void skb_scrub_packet(struct sk_buff *skb, bool xnet) skb->offload_fwd_mark = 0; skb->offload_l3_fwd_mark = 0; #endif - ipvs_reset(skb); - if (!xnet) return; + ipvs_reset(skb); skb->mark = 0; skb_clear_tstamp(skb); } diff --git a/net/ipv4/ip_input.c b/net/ipv4/ip_input.c index 9860178752b8..00f3b328e90a 100644 --- a/net/ipv4/ip_input.c +++ b/net/ipv4/ip_input.c @@ -609,6 +609,7 @@ int ip_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, if (skb == NULL) return NET_RX_DROP; + ipvs_reset(skb); return NF_HOOK(NFPROTO_IPV4, NF_INET_PRE_ROUTING, net, NULL, skb, dev, NULL, ip_rcv_finish); diff --git a/net/ipv6/ip6_input.c b/net/ipv6/ip6_input.c index d332ec60f915..05917095ef6d 100644 --- a/net/ipv6/ip6_input.c +++ b/net/ipv6/ip6_input.c @@ -348,6 +348,7 @@ int ipv6_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt skb = ip6_rcv_core(skb, dev, net); if (skb == NULL) return NET_RX_DROP; + ipvs_reset(skb); return NF_HOOK(NFPROTO_IPV6, NF_INET_PRE_ROUTING, net, NULL, skb, dev, NULL, ip6_rcv_finish); -- 2.25.1