* FAILED: patch "[PATCH] ip: orphan prefetched skbs before multicast forwarding" failed to apply to 5.15-stable tree
@ 2026-09-03 14:00 gregkh
2026-09-08 22:54 ` [PATCH 5.15.y 1/3] inet: frags: add inet_frag_putn() helper Sasha Levin
2026-09-08 22:54 ` [PATCH 5.15.y 1/3] inet: frags: add inet_frag_putn() helper Sasha Levin
0 siblings, 2 replies; 7+ messages in thread
From: gregkh @ 2026-09-03 14:00 UTC (permalink / raw)
To: zhilinz, idosch, pabeni, vega; +Cc: stable
The patch below does not apply to the 5.15-stable tree.
If someone wants it applied there, or to any other stable or longterm
tree, then please email the backport, including the original git commit
id to <stable@vger.kernel.org>.
To reproduce the conflict and resubmit, you may use the following commands:
git fetch https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/ linux-5.15.y
git checkout FETCH_HEAD
git cherry-pick -x e36ce6e78fe3fc3c071a26750783b7ba081ce10d
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<stable@vger.kernel.org>' --in-reply-to '2026090319-antiques-palm-c286@gregkh' --subject-prefix 'PATCH 5.15.y' 'HEAD^..'
Possible dependencies:
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From e36ce6e78fe3fc3c071a26750783b7ba081ce10d Mon Sep 17 00:00:00 2001
From: Zhiling Zou <zhilinz@nebusec.ai>
Date: Thu, 13 Aug 2026 00:36:38 +0800
Subject: [PATCH] ip: orphan prefetched skbs before multicast forwarding
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 <vega@nebusec.ai>
Signed-off-by: Zhiling Zou <zhilinz@nebusec.ai>
Reported-by: Vega <vega@nebusec.ai>
Signed-off-by: Zhiling Zou <zhilinz@nebusec.ai>
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>
diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c
index 1d9a4ac14fce..e5f2b1c6150d 100644
--- a/net/ipv4/ipmr.c
+++ b/net/ipv4/ipmr.c
@@ -2213,6 +2213,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 8972863c93ee..d332ec60f915 100644
--- a/net/ipv6/ip6_input.c
+++ b/net/ipv6/ip6_input.c
@@ -622,6 +622,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;
}
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH 5.15.y 1/3] inet: frags: add inet_frag_putn() helper
2026-09-03 14:00 FAILED: patch "[PATCH] ip: orphan prefetched skbs before multicast forwarding" failed to apply to 5.15-stable tree gregkh
@ 2026-09-08 22:54 ` Sasha Levin
2026-09-08 22:54 ` [PATCH 5.15.y 2/3] ipv4: frags: remove ipq_put() Sasha Levin
2026-09-08 22:54 ` [PATCH 5.15.y 3/3] ip: orphan prefetched skbs before multicast forwarding Sasha Levin
2026-09-08 22:54 ` [PATCH 5.15.y 1/3] inet: frags: add inet_frag_putn() helper Sasha Levin
1 sibling, 2 replies; 7+ messages in thread
From: Sasha Levin @ 2026-09-08 22:54 UTC (permalink / raw)
To: stable; +Cc: Eric Dumazet, Paolo Abeni, Sasha Levin
From: Eric Dumazet <edumazet@google.com>
[ Upstream commit ae2d90355aa5592b0e99c8bbb4c3fa1d8e205f1b ]
inet_frag_putn() can release multiple references
in one step.
Use it in inet_frags_free_cb().
Replace inet_frag_put(X) with inet_frag_putn(X, 1)
Signed-off-by: Eric Dumazet <edumazet@google.com>
Link: https://patch.msgid.link/20250312082250.1803501-2-edumazet@google.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
Stable-dep-of: e36ce6e78fe3 ("ip: orphan prefetched skbs before multicast forwarding")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
include/net/inet_frag.h | 4 ++--
include/net/ipv6_frag.h | 3 ++-
net/ieee802154/6lowpan/reassembly.c | 7 ++++---
net/ipv4/inet_fragment.c | 3 +--
net/ipv4/ip_fragment.c | 2 +-
net/ipv6/netfilter/nf_conntrack_reasm.c | 3 ++-
net/ipv6/reassembly.c | 4 ++--
7 files changed, 14 insertions(+), 12 deletions(-)
diff --git a/include/net/inet_frag.h b/include/net/inet_frag.h
index 63540be0fc34a..5c782c1feb5a1 100644
--- a/include/net/inet_frag.h
+++ b/include/net/inet_frag.h
@@ -136,9 +136,9 @@ struct inet_frag_queue *inet_frag_find(struct fqdir *fqdir, void *key);
/* Free all skbs in the queue; return the sum of their truesizes. */
unsigned int inet_frag_rbtree_purge(struct rb_root *root);
-static inline void inet_frag_put(struct inet_frag_queue *q)
+static inline void inet_frag_putn(struct inet_frag_queue *q, int refs)
{
- if (refcount_dec_and_test(&q->refcnt))
+ if (refs && refcount_sub_and_test(refs, &q->refcnt))
inet_frag_destroy(q);
}
diff --git a/include/net/ipv6_frag.h b/include/net/ipv6_frag.h
index 0a4779175a523..3443c7905b785 100644
--- a/include/net/ipv6_frag.h
+++ b/include/net/ipv6_frag.h
@@ -65,6 +65,7 @@ ip6frag_expire_frag_queue(struct net *net, struct frag_queue *fq)
{
struct net_device *dev = NULL;
struct sk_buff *head;
+ int refs = 1;
rcu_read_lock();
/* Paired with the WRITE_ONCE() in fqdir_pre_exit(). */
@@ -107,7 +108,7 @@ ip6frag_expire_frag_queue(struct net *net, struct frag_queue *fq)
spin_unlock(&fq->q.lock);
out_rcu_unlock:
rcu_read_unlock();
- inet_frag_put(&fq->q);
+ inet_frag_putn(&fq->q, refs);
}
/* Check if the upper layer header is truncated in the first fragment. */
diff --git a/net/ieee802154/6lowpan/reassembly.c b/net/ieee802154/6lowpan/reassembly.c
index be6f06adefe0a..f5b554894d024 100644
--- a/net/ieee802154/6lowpan/reassembly.c
+++ b/net/ieee802154/6lowpan/reassembly.c
@@ -45,6 +45,7 @@ static void lowpan_frag_expire(struct timer_list *t)
{
struct inet_frag_queue *frag = from_timer(frag, t, timer);
struct frag_queue *fq;
+ int refs = 1;
fq = container_of(frag, struct frag_queue, q);
@@ -56,7 +57,7 @@ static void lowpan_frag_expire(struct timer_list *t)
inet_frag_kill(&fq->q);
out:
spin_unlock(&fq->q.lock);
- inet_frag_put(&fq->q);
+ inet_frag_putn(&fq->q, refs);
}
static inline struct lowpan_frag_queue *
@@ -301,13 +302,13 @@ int lowpan_frag_rcv(struct sk_buff *skb, u8 frag_type)
fq = fq_find(net, cb, &hdr.source, &hdr.dest);
if (fq != NULL) {
- int ret;
+ int ret, refs = 1;
spin_lock(&fq->q.lock);
ret = lowpan_frag_queue(fq, skb, frag_type);
spin_unlock(&fq->q.lock);
- inet_frag_put(&fq->q);
+ inet_frag_putn(&fq->q, refs);
return ret;
}
diff --git a/net/ipv4/inet_fragment.c b/net/ipv4/inet_fragment.c
index 6e6b46ebfc407..4de79ee66a1cb 100644
--- a/net/ipv4/inet_fragment.c
+++ b/net/ipv4/inet_fragment.c
@@ -144,8 +144,7 @@ static void inet_frags_free_cb(void *ptr, void *arg)
}
spin_unlock_bh(&fq->lock);
- if (refcount_sub_and_test(count, &fq->refcnt))
- inet_frag_destroy(fq);
+ inet_frag_putn(fq, count);
}
static LLIST_HEAD(fqdir_free_list);
diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c
index 23312d028af28..11dedc82b98da 100644
--- a/net/ipv4/ip_fragment.c
+++ b/net/ipv4/ip_fragment.c
@@ -107,7 +107,7 @@ static void ip4_frag_free(struct inet_frag_queue *q)
static void ipq_put(struct ipq *ipq)
{
- inet_frag_put(&ipq->q);
+ inet_frag_putn(&ipq->q, 1);
}
/* Kill ipq entry. It is not destroyed immediately,
diff --git a/net/ipv6/netfilter/nf_conntrack_reasm.c b/net/ipv6/netfilter/nf_conntrack_reasm.c
index d3b728771737a..dea2ed5f9f5aa 100644
--- a/net/ipv6/netfilter/nf_conntrack_reasm.c
+++ b/net/ipv6/netfilter/nf_conntrack_reasm.c
@@ -448,6 +448,7 @@ int nf_ct_frag6_gather(struct net *net, struct sk_buff *skb, u32 user)
struct frag_hdr *fhdr;
struct frag_queue *fq;
struct ipv6hdr *hdr;
+ int refs = 1;
u8 prevhdr;
/* Jumbo payload inhibits frag. header */
@@ -490,7 +491,7 @@ int nf_ct_frag6_gather(struct net *net, struct sk_buff *skb, u32 user)
}
spin_unlock_bh(&fq->q.lock);
- inet_frag_put(&fq->q);
+ inet_frag_putn(&fq->q, refs);
return ret;
}
EXPORT_SYMBOL_GPL(nf_ct_frag6_gather);
diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c
index 6993675171556..31bfc7932378a 100644
--- a/net/ipv6/reassembly.c
+++ b/net/ipv6/reassembly.c
@@ -374,7 +374,7 @@ static int ipv6_frag_rcv(struct sk_buff *skb)
fq = fq_find(net, fhdr->identification, hdr, iif);
if (fq) {
u32 prob_offset = 0;
- int ret;
+ int ret, refs = 1;
spin_lock(&fq->q.lock);
@@ -383,7 +383,7 @@ static int ipv6_frag_rcv(struct sk_buff *skb)
&prob_offset);
spin_unlock(&fq->q.lock);
- inet_frag_put(&fq->q);
+ inet_frag_putn(&fq->q, refs);
if (prob_offset) {
__IP6_INC_STATS(net, __in6_dev_get_safely(skb->dev),
IPSTATS_MIB_INHDRERRORS);
--
2.53.0
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH 5.15.y 2/3] ipv4: frags: remove ipq_put()
2026-09-08 22:54 ` [PATCH 5.15.y 1/3] inet: frags: add inet_frag_putn() helper Sasha Levin
@ 2026-09-08 22:54 ` Sasha Levin
2026-09-08 22:54 ` [PATCH 5.15.y 3/3] ip: orphan prefetched skbs before multicast forwarding Sasha Levin
1 sibling, 0 replies; 7+ messages in thread
From: Sasha Levin @ 2026-09-08 22:54 UTC (permalink / raw)
To: stable; +Cc: Eric Dumazet, Paolo Abeni, Sasha Levin
From: Eric Dumazet <edumazet@google.com>
[ Upstream commit a2fb987c0ecf0498cc17056339cb11d128c46ab7 ]
Replace ipq_put() with inet_frag_putn()
Signed-off-by: Eric Dumazet <edumazet@google.com>
Link: https://patch.msgid.link/20250312082250.1803501-3-edumazet@google.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
For the stable backport, retain the existing ip_expire() error and skb
freeing paths. Also brace the multicast delivery conditional so that
the dependent fix can add its non-local skb orphaning without conflict.
Stable-dep-of: e36ce6e78fe3 ("ip: orphan prefetched skbs before multicast forwarding")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
net/ipv4/ip_fragment.c | 15 ++++-----------
net/ipv6/ip6_input.c | 4 ++--
2 files changed, 6 insertions(+), 13 deletions(-)
diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c
index 11dedc82b98da..34e85c552ac36 100644
--- a/net/ipv4/ip_fragment.c
+++ b/net/ipv4/ip_fragment.c
@@ -102,14 +102,6 @@ static void ip4_frag_free(struct inet_frag_queue *q)
inet_putpeer(qp->peer);
}
-
-/* Destruction primitives. */
-
-static void ipq_put(struct ipq *ipq)
-{
- inet_frag_putn(&ipq->q, 1);
-}
-
/* Kill ipq entry. It is not destroyed immediately,
* because caller (and someone more) holds reference count.
*/
@@ -138,6 +130,7 @@ static void ip_expire(struct timer_list *t)
struct net *net;
struct ipq *qp;
int err;
+ int refs = 1;
qp = container_of(frag, struct ipq, q);
net = qp->q.fqdir->net;
@@ -195,7 +188,7 @@ static void ip_expire(struct timer_list *t)
out_rcu_unlock:
rcu_read_unlock();
kfree_skb(head);
- ipq_put(qp);
+ inet_frag_putn(&qp->q, refs);
}
/* Find the correct entry in the "incomplete datagrams" queue for
@@ -484,14 +477,14 @@ int ip_defrag(struct net *net, struct sk_buff *skb, u32 user)
/* Lookup (or create) queue header */
qp = ip_find(net, ip_hdr(skb), user, vif);
if (qp) {
- int ret;
+ int ret, refs = 1;
spin_lock(&qp->q.lock);
ret = ip_frag_queue(qp, skb);
spin_unlock(&qp->q.lock);
- ipq_put(qp);
+ inet_frag_putn(&qp->q, refs);
return ret;
}
diff --git a/net/ipv6/ip6_input.c b/net/ipv6/ip6_input.c
index cf577cc3b48cf..94d2ab8689d88 100644
--- a/net/ipv6/ip6_input.c
+++ b/net/ipv6/ip6_input.c
@@ -552,9 +552,9 @@ int ip6_mc_input(struct sk_buff *skb)
/* unknown RA - process it normally */
}
- if (deliver)
+ if (deliver) {
skb2 = skb_clone(skb, GFP_ATOMIC);
- else {
+ } else {
skb2 = skb;
skb = NULL;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH 5.15.y 3/3] ip: orphan prefetched skbs before multicast forwarding
2026-09-08 22:54 ` [PATCH 5.15.y 1/3] inet: frags: add inet_frag_putn() helper Sasha Levin
2026-09-08 22:54 ` [PATCH 5.15.y 2/3] ipv4: frags: remove ipq_put() Sasha Levin
@ 2026-09-08 22:54 ` Sasha Levin
1 sibling, 0 replies; 7+ messages in thread
From: Sasha Levin @ 2026-09-08 22:54 UTC (permalink / raw)
To: stable; +Cc: Zhiling Zou, Vega, Ido Schimmel, Paolo Abeni, Sasha Levin
From: Zhiling Zou <zhilinz@nebusec.ai>
[ 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 <vega@nebusec.ai>
Signed-off-by: Zhiling Zou <zhilinz@nebusec.ai>
Reported-by: Vega <vega@nebusec.ai>
Signed-off-by: Zhiling Zou <zhilinz@nebusec.ai>
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 5e582eab1ea19..5ef20e8467e31 100644
--- a/net/ipv4/ipmr.c
+++ b/net/ipv4/ipmr.c
@@ -2100,6 +2100,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 94d2ab8689d88..403697fa5569d 100644
--- a/net/ipv6/ip6_input.c
+++ b/net/ipv6/ip6_input.c
@@ -555,6 +555,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
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH 5.15.y 1/3] inet: frags: add inet_frag_putn() helper
2026-09-03 14:00 FAILED: patch "[PATCH] ip: orphan prefetched skbs before multicast forwarding" failed to apply to 5.15-stable tree gregkh
2026-09-08 22:54 ` [PATCH 5.15.y 1/3] inet: frags: add inet_frag_putn() helper Sasha Levin
@ 2026-09-08 22:54 ` Sasha Levin
2026-09-08 22:54 ` [PATCH 5.15.y 2/3] ipv4: frags: remove ipq_put() Sasha Levin
2026-09-08 22:54 ` [PATCH 5.15.y 3/3] ip: orphan prefetched skbs before multicast forwarding Sasha Levin
1 sibling, 2 replies; 7+ messages in thread
From: Sasha Levin @ 2026-09-08 22:54 UTC (permalink / raw)
To: stable; +Cc: Eric Dumazet, Paolo Abeni, Sasha Levin
From: Eric Dumazet <edumazet@google.com>
[ Upstream commit ae2d90355aa5592b0e99c8bbb4c3fa1d8e205f1b ]
inet_frag_putn() can release multiple references
in one step.
Use it in inet_frags_free_cb().
Replace inet_frag_put(X) with inet_frag_putn(X, 1)
Signed-off-by: Eric Dumazet <edumazet@google.com>
Link: https://patch.msgid.link/20250312082250.1803501-2-edumazet@google.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
Stable-dep-of: e36ce6e78fe3 ("ip: orphan prefetched skbs before multicast forwarding")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
include/net/inet_frag.h | 4 ++--
include/net/ipv6_frag.h | 3 ++-
net/ieee802154/6lowpan/reassembly.c | 7 ++++---
net/ipv4/inet_fragment.c | 3 +--
net/ipv4/ip_fragment.c | 2 +-
net/ipv6/netfilter/nf_conntrack_reasm.c | 3 ++-
net/ipv6/reassembly.c | 4 ++--
7 files changed, 14 insertions(+), 12 deletions(-)
diff --git a/include/net/inet_frag.h b/include/net/inet_frag.h
index 63540be0fc34a..5c782c1feb5a1 100644
--- a/include/net/inet_frag.h
+++ b/include/net/inet_frag.h
@@ -136,9 +136,9 @@ struct inet_frag_queue *inet_frag_find(struct fqdir *fqdir, void *key);
/* Free all skbs in the queue; return the sum of their truesizes. */
unsigned int inet_frag_rbtree_purge(struct rb_root *root);
-static inline void inet_frag_put(struct inet_frag_queue *q)
+static inline void inet_frag_putn(struct inet_frag_queue *q, int refs)
{
- if (refcount_dec_and_test(&q->refcnt))
+ if (refs && refcount_sub_and_test(refs, &q->refcnt))
inet_frag_destroy(q);
}
diff --git a/include/net/ipv6_frag.h b/include/net/ipv6_frag.h
index 0a4779175a523..3443c7905b785 100644
--- a/include/net/ipv6_frag.h
+++ b/include/net/ipv6_frag.h
@@ -65,6 +65,7 @@ ip6frag_expire_frag_queue(struct net *net, struct frag_queue *fq)
{
struct net_device *dev = NULL;
struct sk_buff *head;
+ int refs = 1;
rcu_read_lock();
/* Paired with the WRITE_ONCE() in fqdir_pre_exit(). */
@@ -107,7 +108,7 @@ ip6frag_expire_frag_queue(struct net *net, struct frag_queue *fq)
spin_unlock(&fq->q.lock);
out_rcu_unlock:
rcu_read_unlock();
- inet_frag_put(&fq->q);
+ inet_frag_putn(&fq->q, refs);
}
/* Check if the upper layer header is truncated in the first fragment. */
diff --git a/net/ieee802154/6lowpan/reassembly.c b/net/ieee802154/6lowpan/reassembly.c
index be6f06adefe0a..f5b554894d024 100644
--- a/net/ieee802154/6lowpan/reassembly.c
+++ b/net/ieee802154/6lowpan/reassembly.c
@@ -45,6 +45,7 @@ static void lowpan_frag_expire(struct timer_list *t)
{
struct inet_frag_queue *frag = from_timer(frag, t, timer);
struct frag_queue *fq;
+ int refs = 1;
fq = container_of(frag, struct frag_queue, q);
@@ -56,7 +57,7 @@ static void lowpan_frag_expire(struct timer_list *t)
inet_frag_kill(&fq->q);
out:
spin_unlock(&fq->q.lock);
- inet_frag_put(&fq->q);
+ inet_frag_putn(&fq->q, refs);
}
static inline struct lowpan_frag_queue *
@@ -301,13 +302,13 @@ int lowpan_frag_rcv(struct sk_buff *skb, u8 frag_type)
fq = fq_find(net, cb, &hdr.source, &hdr.dest);
if (fq != NULL) {
- int ret;
+ int ret, refs = 1;
spin_lock(&fq->q.lock);
ret = lowpan_frag_queue(fq, skb, frag_type);
spin_unlock(&fq->q.lock);
- inet_frag_put(&fq->q);
+ inet_frag_putn(&fq->q, refs);
return ret;
}
diff --git a/net/ipv4/inet_fragment.c b/net/ipv4/inet_fragment.c
index 6e6b46ebfc407..4de79ee66a1cb 100644
--- a/net/ipv4/inet_fragment.c
+++ b/net/ipv4/inet_fragment.c
@@ -144,8 +144,7 @@ static void inet_frags_free_cb(void *ptr, void *arg)
}
spin_unlock_bh(&fq->lock);
- if (refcount_sub_and_test(count, &fq->refcnt))
- inet_frag_destroy(fq);
+ inet_frag_putn(fq, count);
}
static LLIST_HEAD(fqdir_free_list);
diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c
index 23312d028af28..11dedc82b98da 100644
--- a/net/ipv4/ip_fragment.c
+++ b/net/ipv4/ip_fragment.c
@@ -107,7 +107,7 @@ static void ip4_frag_free(struct inet_frag_queue *q)
static void ipq_put(struct ipq *ipq)
{
- inet_frag_put(&ipq->q);
+ inet_frag_putn(&ipq->q, 1);
}
/* Kill ipq entry. It is not destroyed immediately,
diff --git a/net/ipv6/netfilter/nf_conntrack_reasm.c b/net/ipv6/netfilter/nf_conntrack_reasm.c
index d3b728771737a..dea2ed5f9f5aa 100644
--- a/net/ipv6/netfilter/nf_conntrack_reasm.c
+++ b/net/ipv6/netfilter/nf_conntrack_reasm.c
@@ -448,6 +448,7 @@ int nf_ct_frag6_gather(struct net *net, struct sk_buff *skb, u32 user)
struct frag_hdr *fhdr;
struct frag_queue *fq;
struct ipv6hdr *hdr;
+ int refs = 1;
u8 prevhdr;
/* Jumbo payload inhibits frag. header */
@@ -490,7 +491,7 @@ int nf_ct_frag6_gather(struct net *net, struct sk_buff *skb, u32 user)
}
spin_unlock_bh(&fq->q.lock);
- inet_frag_put(&fq->q);
+ inet_frag_putn(&fq->q, refs);
return ret;
}
EXPORT_SYMBOL_GPL(nf_ct_frag6_gather);
diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c
index 6993675171556..31bfc7932378a 100644
--- a/net/ipv6/reassembly.c
+++ b/net/ipv6/reassembly.c
@@ -374,7 +374,7 @@ static int ipv6_frag_rcv(struct sk_buff *skb)
fq = fq_find(net, fhdr->identification, hdr, iif);
if (fq) {
u32 prob_offset = 0;
- int ret;
+ int ret, refs = 1;
spin_lock(&fq->q.lock);
@@ -383,7 +383,7 @@ static int ipv6_frag_rcv(struct sk_buff *skb)
&prob_offset);
spin_unlock(&fq->q.lock);
- inet_frag_put(&fq->q);
+ inet_frag_putn(&fq->q, refs);
if (prob_offset) {
__IP6_INC_STATS(net, __in6_dev_get_safely(skb->dev),
IPSTATS_MIB_INHDRERRORS);
--
2.53.0
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH 5.15.y 2/3] ipv4: frags: remove ipq_put()
2026-09-08 22:54 ` [PATCH 5.15.y 1/3] inet: frags: add inet_frag_putn() helper Sasha Levin
@ 2026-09-08 22:54 ` Sasha Levin
2026-09-08 22:54 ` [PATCH 5.15.y 3/3] ip: orphan prefetched skbs before multicast forwarding Sasha Levin
1 sibling, 0 replies; 7+ messages in thread
From: Sasha Levin @ 2026-09-08 22:54 UTC (permalink / raw)
To: stable; +Cc: Eric Dumazet, Paolo Abeni, Sasha Levin
From: Eric Dumazet <edumazet@google.com>
[ Upstream commit a2fb987c0ecf0498cc17056339cb11d128c46ab7 ]
Replace ipq_put() with inet_frag_putn()
Signed-off-by: Eric Dumazet <edumazet@google.com>
Link: https://patch.msgid.link/20250312082250.1803501-3-edumazet@google.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
For the stable backport, retain the existing ip_expire() error and skb
freeing paths. Also brace the multicast delivery conditional so that
the dependent fix can add its non-local skb orphaning without conflict.
Stable-dep-of: e36ce6e78fe3 ("ip: orphan prefetched skbs before multicast forwarding")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
net/ipv4/ip_fragment.c | 15 ++++-----------
net/ipv6/ip6_input.c | 4 ++--
2 files changed, 6 insertions(+), 13 deletions(-)
diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c
index 11dedc82b98da..34e85c552ac36 100644
--- a/net/ipv4/ip_fragment.c
+++ b/net/ipv4/ip_fragment.c
@@ -102,14 +102,6 @@ static void ip4_frag_free(struct inet_frag_queue *q)
inet_putpeer(qp->peer);
}
-
-/* Destruction primitives. */
-
-static void ipq_put(struct ipq *ipq)
-{
- inet_frag_putn(&ipq->q, 1);
-}
-
/* Kill ipq entry. It is not destroyed immediately,
* because caller (and someone more) holds reference count.
*/
@@ -138,6 +130,7 @@ static void ip_expire(struct timer_list *t)
struct net *net;
struct ipq *qp;
int err;
+ int refs = 1;
qp = container_of(frag, struct ipq, q);
net = qp->q.fqdir->net;
@@ -195,7 +188,7 @@ static void ip_expire(struct timer_list *t)
out_rcu_unlock:
rcu_read_unlock();
kfree_skb(head);
- ipq_put(qp);
+ inet_frag_putn(&qp->q, refs);
}
/* Find the correct entry in the "incomplete datagrams" queue for
@@ -484,14 +477,14 @@ int ip_defrag(struct net *net, struct sk_buff *skb, u32 user)
/* Lookup (or create) queue header */
qp = ip_find(net, ip_hdr(skb), user, vif);
if (qp) {
- int ret;
+ int ret, refs = 1;
spin_lock(&qp->q.lock);
ret = ip_frag_queue(qp, skb);
spin_unlock(&qp->q.lock);
- ipq_put(qp);
+ inet_frag_putn(&qp->q, refs);
return ret;
}
diff --git a/net/ipv6/ip6_input.c b/net/ipv6/ip6_input.c
index cf577cc3b48cf..94d2ab8689d88 100644
--- a/net/ipv6/ip6_input.c
+++ b/net/ipv6/ip6_input.c
@@ -552,9 +552,9 @@ int ip6_mc_input(struct sk_buff *skb)
/* unknown RA - process it normally */
}
- if (deliver)
+ if (deliver) {
skb2 = skb_clone(skb, GFP_ATOMIC);
- else {
+ } else {
skb2 = skb;
skb = NULL;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH 5.15.y 3/3] ip: orphan prefetched skbs before multicast forwarding
2026-09-08 22:54 ` [PATCH 5.15.y 1/3] inet: frags: add inet_frag_putn() helper Sasha Levin
2026-09-08 22:54 ` [PATCH 5.15.y 2/3] ipv4: frags: remove ipq_put() Sasha Levin
@ 2026-09-08 22:54 ` Sasha Levin
1 sibling, 0 replies; 7+ messages in thread
From: Sasha Levin @ 2026-09-08 22:54 UTC (permalink / raw)
To: stable; +Cc: Zhiling Zou, Vega, Ido Schimmel, Paolo Abeni, Sasha Levin
From: Zhiling Zou <zhilinz@nebusec.ai>
[ 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 <vega@nebusec.ai>
Signed-off-by: Zhiling Zou <zhilinz@nebusec.ai>
Reported-by: Vega <vega@nebusec.ai>
Signed-off-by: Zhiling Zou <zhilinz@nebusec.ai>
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 5e582eab1ea19..5ef20e8467e31 100644
--- a/net/ipv4/ipmr.c
+++ b/net/ipv4/ipmr.c
@@ -2100,6 +2100,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 94d2ab8689d88..403697fa5569d 100644
--- a/net/ipv6/ip6_input.c
+++ b/net/ipv6/ip6_input.c
@@ -555,6 +555,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
^ permalink raw reply related [flat|nested] 7+ messages in thread
end of thread, other threads:[~2026-09-08 22:54 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-03 14:00 FAILED: patch "[PATCH] ip: orphan prefetched skbs before multicast forwarding" failed to apply to 5.15-stable tree gregkh
2026-09-08 22:54 ` [PATCH 5.15.y 1/3] inet: frags: add inet_frag_putn() helper Sasha Levin
2026-09-08 22:54 ` [PATCH 5.15.y 2/3] ipv4: frags: remove ipq_put() Sasha Levin
2026-09-08 22:54 ` [PATCH 5.15.y 3/3] ip: orphan prefetched skbs before multicast forwarding Sasha Levin
2026-09-08 22:54 ` [PATCH 5.15.y 1/3] inet: frags: add inet_frag_putn() helper Sasha Levin
2026-09-08 22:54 ` [PATCH 5.15.y 2/3] ipv4: frags: remove ipq_put() Sasha Levin
2026-09-08 22:54 ` [PATCH 5.15.y 3/3] ip: orphan prefetched skbs before multicast forwarding Sasha Levin
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox