FAILED: patch "[PATCH] xfrm: hold dev ref until after transport_finish NF_HOOK" failed to apply to 6.12-stable tree
Subsystems (3)
[email protected]
maintainerThe patch below does not apply to the 6.12-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-6.12.y
git checkout FETCH_HEAD
git cherry-pick -x 1c428b03840094410c5fb6a5db30640486bbbfcb
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<[email protected]>' --in-reply-to '2026041350-debunk-desktop-efbf@gregkh' --subject-prefix 'PATCH 6.12.y' HEAD^..
Possible dependencies:
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From 1c428b03840094410c5fb6a5db30640486bbbfcb Mon Sep 17 00:00:00 2001
From: Qi Tang <[email protected]>
Date: Thu, 2 Apr 2026 19:44:01 +0800
Subject: [PATCH] xfrm: hold dev ref until after transport_finish NF_HOOK
After async crypto completes, xfrm_input_resume() calls dev_put() immediately on re-entry before the skb reaches transport_finish. The skb->dev pointer is then used inside NF_HOOK and its okfn, which can race with device teardown.
Remove the dev_put from the async resumption entry and instead drop the reference after the NF_HOOK call in transport_finish, using a saved device pointer since NF_HOOK may consume the skb. This covers NF_DROP, NF_QUEUE and NF_STOLEN paths that skip the okfn.
For non-transport exits (decaps, gro, drop) and secondary async return points, release the reference inline when async is set.
net/ipv4/xfrm4_input.c +4 -1
@@ -50,6 +50,7 @@ int xfrm4_transport_finish(struct sk_buff *skb, int async) {struct xfrm_offload *xo =xfrm_offload (skb);struct iphdr *iph =ip_hdr (skb); +struct net_device *dev = skb->dev; iph->protocol =XFRM_MODE_SKB_CB (skb)->protocol;
@@ -73,8 +74,10 @@ int xfrm4_transport_finish(struct sk_buff *skb, int async) }NF_HOOK (NFPROTO_IPV4 ,NF_INET_PRE_ROUTING , -dev_net (skb->dev),NULL , skb, skb->dev,NULL , +dev_net (dev),NULL , skb, dev,NULL , xfrm4_rcv_encap_finish); +if (async) +dev_put (dev);return 0 ; }
net/ipv6/xfrm6_input.c +4 -1
@@ -43,6 +43,7 @@ static int xfrm6_transport_finish2(struct net *net, struct sock *sk,int xfrm6_transport_finish (struct sk_buff *skb,int async) {struct xfrm_offload *xo =xfrm_offload (skb); +struct net_device *dev = skb->dev;int nhlen = -skb_network_offset (skb); skb_network_header(skb)[IP6CB(skb)->nhoff] =
@@ -68,8 +69,10 @@ int xfrm6_transport_finish(struct sk_buff *skb, int async) }NF_HOOK (NFPROTO_IPV6 ,NF_INET_PRE_ROUTING , -dev_net (skb->dev),NULL , skb, skb->dev,NULL , +dev_net (dev),NULL , skb, dev,NULL , xfrm6_transport_finish2); +if (async) +dev_put (dev);return 0 ; }
net/xfrm/xfrm_input.c +14 -4
@@ -506,7 +506,6 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type)/* An encap_type of -1 indicates async resumption. */ if (encap_type ==-1 ) { async =1 ; -dev_put (skb->dev); seq =XFRM_SKB_CB (skb)->seq.input.low;spin_lock (&x->lock); goto resume;
@@ -659,8 +658,11 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type)dev_hold (skb->dev); nexthdr = x->type->input (x, skb); -if (nexthdr == -EINPROGRESS ) +if (nexthdr == -EINPROGRESS ) { +if (async) +dev_put (skb->dev);return 0 ; + }dev_put (skb->dev);spin_lock (&x->lock);
@@ -695,9 +697,11 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type)XFRM_MODE_SKB_CB (skb)->protocol = nexthdr; err =xfrm_inner_mode_input (x, skb); -if (err == -EINPROGRESS ) +if (err == -EINPROGRESS ) { +if (async) +dev_put (skb->dev);return 0 ; -else if (err) { + }else if (err) {XFRM_INC_STATS (net,LINUX_MIB_XFRMINSTATEMODEERROR ); goto drop; }
@@ -734,6 +738,8 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type) sp->olen =0 ;if (skb_valid_dst (skb))skb_dst_drop (skb); +if (async) +dev_put (skb->dev);gro_cells_receive (&gro_cells, skb);return 0 ; }else {
@@ -753,6 +759,8 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type) sp->olen =0 ;if (skb_valid_dst (skb))skb_dst_drop (skb); +if (async) +dev_put (skb->dev);gro_cells_receive (&gro_cells, skb);return err; }
@@ -763,6 +771,8 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type) drop_unlock:spin_unlock (&x->lock); drop: +if (async) +dev_put (skb->dev);xfrm_rcv_cb (skb, family, x && x->type ? x->type->proto : nexthdr,-1 );kfree_skb (skb);return 0 ;