FAILED: patch "[PATCH] ip: orphan prefetched skbs before multicast forwarding" failed to apply to 5.10-stable tree
Subsystems (3)
[email protected]
maintainerThe patch below does not apply to the 5.10-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 <[email protected]>.
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.10.y
git checkout FETCH_HEAD
git cherry-pick -x e36ce6e78fe3fc3c071a26750783b7ba081ce10d
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<[email protected]>' --in-reply-to '2026090320-tiptop-scrooge-9ea0@gregkh' --subject-prefix 'PATCH 5.10.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 <[email protected]>
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.
net/ipv4/ipmr.c +3 -0
@@ -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);
net/ipv6/ip6_input.c +1 -0
@@ -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 ; }
Sasha Levin
maintainerPATCH 1/3 inet: frags: add inet_frag_putn() helper
From: Eric Dumazet <[email protected]>
[ 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)
Stable-dep-of: e36ce6e78fe3 ("ip: orphan prefetched skbs before multicast forwarding")
--- 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(-)
include/net/inet_frag.h +2 -2
@@ -135,9 +135,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); }
include/net/ipv6_frag.h +2 -1
@@ -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. */
net/ieee802154/6lowpan/reassembly.c +4 -3
@@ -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; }
net/ipv4/inet_fragment.c +1 -2
@@ -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 void fqdir_work_fn (struct work_struct *work)
net/ipv4/ip_fragment.c +1 -1
@@ -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,
net/ipv6/netfilter/nf_conntrack_reasm.c +2 -1
@@ -447,6 +447,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 */
@@ -489,7 +490,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);
net/ipv6/reassembly.c +2 -2
@@ -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 );
Signature · 1 line
2.53.0
Sasha Levin
maintainerPATCH 2/3 ipv4: frags: remove ipq_put()
From: Eric Dumazet <[email protected]>
[ Upstream commit a2fb987c0ecf0498cc17056339cb11d128c46ab7 ]
Replace ipq_put() with inet_frag_putn()
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")
--- net/ipv4/ip_fragment.c | 15 ++++----------- net/ipv6/ip6_input.c | 4 ++-- 2 files changed, 6 insertions(+), 13 deletions(-)
net/ipv4/ip_fragment.c +4 -11
@@ -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; }
net/ipv6/ip6_input.c +2 -2
@@ -554,9 +554,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 ; }
Signature · 1 line
2.53.0
Sasha Levin
maintainerPATCH 3/3 ip: orphan prefetched skbs before multicast forwarding
In reply to Sasha LevinFrom: Zhiling Zou <[email protected]>
[ 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.
--- net/ipv4/ipmr.c | 3 +++ net/ipv6/ip6_input.c | 1 + 2 files changed, 4 insertions(+)
net/ipv4/ipmr.c +3 -0
@@ -2112,6 +2112,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);
net/ipv6/ip6_input.c +1 -0
@@ -557,6 +557,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 ; }
Signature · 1 line
2.53.0