[PATCH net v7 1/3] xfrm: use skb->dev before dropping the reference held across async

From: Qihang

Date: Mon Oct 26 2026 - 22:55:10 EST


The skb->dev reference that is held across an async resumption is
released before skb->dev is used, on two exits of xfrm_input():

- the drop path runs the receive callbacks after the reference is
dropped; xfrmi_rcv_cb() reads skb->dev->ifindex, so it can race a
concurrent teardown of the device
- the decaps success exit calls gro_cells_receive() after the
reference is dropped; gro_cells_receive() reads skb->dev

Use skb->dev first and drop the reference afterwards in both cases,
matching what the transport exit already does.

The early drop for a state that is no longer valid releases the
reference on its own; let the drop label handle that reference too.

Fixes: 1c428b038400 ("xfrm: hold dev ref until after transport_finish NF_HOOK")
Cc: stable@xxxxxxxxxxxxxxx
Signed-off-by: Qihang <q.h.hack.winter@xxxxxxxxx>
---
v7:
- also move the reference drop below gro_cells_receive() in the decaps
success exit, which used skb->dev after the reference was dropped
(found by the netdev AI review).

net/xfrm/xfrm_input.c | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/net/xfrm/xfrm_input.c b/net/xfrm/xfrm_input.c
index 5ed87d51392a5..cfd5cea033127 100644
--- a/net/xfrm/xfrm_input.c
+++ b/net/xfrm/xfrm_input.c
@@ -496,7 +496,7 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type)
LINUX_MIB_XFRMINSTATEINVALID);

if (encap_type == -1)
- dev_put(dev);
+ async = 1;
goto drop;
}

@@ -747,9 +747,10 @@ 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);
+ /* gro_cells_receive() reads skb->dev. */
+ gro_cells_receive(&gro_cells, skb);
if (async)
dev_put(dev);
- gro_cells_receive(&gro_cells, skb);
rcu_read_unlock();
return 0;
} else {
@@ -779,9 +780,9 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type)
drop_unlock:
spin_unlock(&x->lock);
drop:
+ xfrm_rcv_cb(skb, family, xfrm_proto, -1);
if (async)
dev_put(dev);
- xfrm_rcv_cb(skb, family, xfrm_proto, -1);
kfree_skb(skb);
return 0;
}
--
2.54.0 (Apple Git-157)