[PATCH 6.6.y 3/3] ip: orphan prefetched skbs before multicast forwarding
From: Sasha Levin <sashal@kernel.org>
Date: 2026-09-08 19:28:39
Subsystem:
networking [general], networking [ipv4/ipv6], the rest · Maintainers:
"David S. Miller", Eric Dumazet, Jakub Kicinski, Paolo Abeni, David Ahern, Ido Schimmel, Linus Torvalds
From: Zhiling Zou <redacted>
[ Upstream commit e36ce6e78fe3fc3c071a26750783b7ba081ce10d ]
IPv4 and IPv6 input preserve an skb->sk association installed by
bpf_sk_assign() so that local delivery can use the selected socket under
RCU. Both address families can also prefetch a socket in UDP early demux.
In both paths (BPF and UDP early demux) a reference is not guaranteed to
be held on the socket.
When a multicast packet is not locally deliverable, IPv6 hands the
original skb to ip6_mr_input(). IPv4's ip_mr_input() similarly keeps the
original skb when local delivery is not needed. Either path can put the
skb on an unresolved multicast route queue or forward it after the
receive-side RCU section ends.
After the prefetched socket is destroyed, a later skb free invokes
sock_pfree() and dereferences the stale skb->sk. Orphan the skb before
each non-local multicast forwarding path. Local delivery retains the
original skb; the existing skb_clone() calls provide multicast forwarding
with a socket-free clone.
Fixes: cf7fbe660f2d ("bpf: Add socket assign support")
Fixes: 08842c43d016 ("udp: no longer touch sk->sk_refcnt in early demux")
Cc: stable@vger.kernel.org
Reported-by: Vega <redacted>
Signed-off-by: Zhiling Zou <redacted>
Reported-by: Vega <redacted>
Signed-off-by: Zhiling Zou <redacted>
Reviewed-by: Ido Schimmel <idosch@nvidia.com>
Link: https://patch.msgid.link/0c52eb3d7532aaf8bccf37e0f7c922143c639735.1786552223.git.zhilinz@nebusec.ai
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
net/ipv4/ipmr.c | 3 +++
net/ipv6/ip6_input.c | 1 +
2 files changed, 4 insertions(+)
diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c
index af9412a507cf3..93d08e343a256 100644
--- a/net/ipv4/ipmr.c
+++ b/net/ipv4/ipmr.c@@ -2139,6 +2139,9 @@ int ip_mr_input(struct sk_buff *skb) if (IPCB(skb)->flags & IPSKB_FORWARDED) goto dont_forward; + if (!local) + skb_orphan(skb); + mrt = ipmr_rt_fib_lookup(net, skb); if (IS_ERR(mrt)) { kfree_skb(skb);
diff --git a/net/ipv6/ip6_input.c b/net/ipv6/ip6_input.c
index e775a5a766692..9b6eaae0c6c80 100644
--- a/net/ipv6/ip6_input.c
+++ b/net/ipv6/ip6_input.c@@ -566,6 +566,7 @@ int ip6_mc_input(struct sk_buff *skb) if (deliver) { skb2 = skb_clone(skb, GFP_ATOMIC); } else { + skb_orphan(skb); skb2 = skb; skb = NULL; }
--
2.53.0