* [PATCH net] xfrm: Fix dev use-after-free in xfrm async resumption
@ 2026-05-29 9:21 Dong Chenchen
2026-06-01 6:32 ` Steffen Klassert
0 siblings, 1 reply; 5+ messages in thread
From: Dong Chenchen @ 2026-05-29 9:21 UTC (permalink / raw)
To: steffen.klassert, herbert, davem, edumazet, kuba, pabeni, horms,
tpluszz77
Cc: netdev, zhangchangzhong, xuchunxiao3, Dong Chenchen
xfrm async resumption hold skb->dev refcnt until after transport_finish.
However, xfrm_rcv_cb may modify skb->dev to tunnel dev without taking
device reference, such as vti_rcv_cb. The subsequent async resumption
will decrement the tunnel device's reference count, which lead to uaf
of tunnel dev and refcnt leak of orig dev as below:
unregister_netdevice: waiting for vti1 to become free. Usage count = -2
Release refcnt of the original dev after tunnel rcv modify skb->dev to
fix it.
Fixes: 1c428b038400 ("xfrm: hold dev ref until after transport_finish NF_HOOK")
Reported-by: Xu Chunxiao <xuchunxiao3@huawei.com>
Signed-off-by: Dong Chenchen <dongchenchen2@huawei.com>
---
net/xfrm/xfrm_input.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/net/xfrm/xfrm_input.c b/net/xfrm/xfrm_input.c
index f65291eba1f6..c979872b6006 100644
--- a/net/xfrm/xfrm_input.c
+++ b/net/xfrm/xfrm_input.c
@@ -467,6 +467,7 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type)
{
const struct xfrm_state_afinfo *afinfo;
struct net *net = dev_net(skb->dev);
+ struct net_device *dev = skb->dev;
int err;
__be32 seq;
__be32 seq_hi;
@@ -730,6 +731,10 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type)
if (err)
goto drop;
+ if (async && skb->dev != dev) {
+ dev_put(dev);
+ async = 0;
+ }
nf_reset_ct(skb);
if (decaps) {
--
2.25.1
^ permalink raw reply related [flat|nested] 5+ messages in thread* Re: [PATCH net] xfrm: Fix dev use-after-free in xfrm async resumption 2026-05-29 9:21 [PATCH net] xfrm: Fix dev use-after-free in xfrm async resumption Dong Chenchen @ 2026-06-01 6:32 ` Steffen Klassert 2026-06-01 12:17 ` dongchenchen (A) 0 siblings, 1 reply; 5+ messages in thread From: Steffen Klassert @ 2026-06-01 6:32 UTC (permalink / raw) To: Dong Chenchen Cc: herbert, davem, edumazet, kuba, pabeni, horms, tpluszz77, netdev, zhangchangzhong, xuchunxiao3 On Fri, May 29, 2026 at 05:21:11PM +0800, Dong Chenchen wrote: > xfrm async resumption hold skb->dev refcnt until after transport_finish. > However, xfrm_rcv_cb may modify skb->dev to tunnel dev without taking > device reference, such as vti_rcv_cb. The subsequent async resumption > will decrement the tunnel device's reference count, which lead to uaf > of tunnel dev and refcnt leak of orig dev as below: > > unregister_netdevice: waiting for vti1 to become free. Usage count = -2 > > Release refcnt of the original dev after tunnel rcv modify skb->dev to > fix it. > > Fixes: 1c428b038400 ("xfrm: hold dev ref until after transport_finish NF_HOOK") > Reported-by: Xu Chunxiao <xuchunxiao3@huawei.com> > Signed-off-by: Dong Chenchen <dongchenchen2@huawei.com> > --- > net/xfrm/xfrm_input.c | 5 +++++ > 1 file changed, 5 insertions(+) > > diff --git a/net/xfrm/xfrm_input.c b/net/xfrm/xfrm_input.c > index f65291eba1f6..c979872b6006 100644 > --- a/net/xfrm/xfrm_input.c > +++ b/net/xfrm/xfrm_input.c > @@ -467,6 +467,7 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type) > { > const struct xfrm_state_afinfo *afinfo; > struct net *net = dev_net(skb->dev); > + struct net_device *dev = skb->dev; > int err; > __be32 seq; > __be32 seq_hi; > @@ -730,6 +731,10 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type) > if (err) > goto drop; > > + if (async && skb->dev != dev) { > + dev_put(dev); > + async = 0; > + } > nf_reset_ct(skb); > > if (decaps) { Sashiko found issues with this patch: https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20260529092111.1089315-1-dongchenchen2%40huawei.com Please review! ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH net] xfrm: Fix dev use-after-free in xfrm async resumption 2026-06-01 6:32 ` Steffen Klassert @ 2026-06-01 12:17 ` dongchenchen (A) 2026-06-02 7:38 ` dongchenchen (A) 0 siblings, 1 reply; 5+ messages in thread From: dongchenchen (A) @ 2026-06-01 12:17 UTC (permalink / raw) To: Steffen Klassert Cc: herbert, davem, edumazet, kuba, pabeni, horms, tpluszz77, netdev, zhangchangzhong, xuchunxiao3 > On Fri, May 29, 2026 at 05:21:11PM +0800, Dong Chenchen wrote: >> xfrm async resumption hold skb->dev refcnt until after transport_finish. >> However, xfrm_rcv_cb may modify skb->dev to tunnel dev without taking >> device reference, such as vti_rcv_cb. The subsequent async resumption >> will decrement the tunnel device's reference count, which lead to uaf >> of tunnel dev and refcnt leak of orig dev as below: >> >> unregister_netdevice: waiting for vti1 to become free. Usage count = -2 >> >> Release refcnt of the original dev after tunnel rcv modify skb->dev to >> fix it. >> >> Fixes: 1c428b038400 ("xfrm: hold dev ref until after transport_finish NF_HOOK") >> Reported-by: Xu Chunxiao <xuchunxiao3@huawei.com> >> Signed-off-by: Dong Chenchen <dongchenchen2@huawei.com> >> --- >> net/xfrm/xfrm_input.c | 5 +++++ >> 1 file changed, 5 insertions(+) >> >> diff --git a/net/xfrm/xfrm_input.c b/net/xfrm/xfrm_input.c >> index f65291eba1f6..c979872b6006 100644 >> --- a/net/xfrm/xfrm_input.c >> +++ b/net/xfrm/xfrm_input.c >> @@ -467,6 +467,7 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type) >> { >> const struct xfrm_state_afinfo *afinfo; >> struct net *net = dev_net(skb->dev); >> + struct net_device *dev = skb->dev; >> int err; >> __be32 seq; >> __be32 seq_hi; >> @@ -730,6 +731,10 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type) >> if (err) >> goto drop; >> >> + if (async && skb->dev != dev) { >> + dev_put(dev); >> + async = 0; >> + } >> nf_reset_ct(skb); >> >> if (decaps) { > Sashiko found issues with this patch: > > https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20260529092111.1089315-1-dongchenchen2%40huawei.com > > Please review! > Hi, Steffen! Thanks a lot for your review. This patch indeed cannot fix all the issues in the branches. Maybe we can stash original skb->dev and move dev_put in transport_finish to xfrm_input to fix it. But there is a question, xfrm_rcv_cb modify skb->dev to tunnel or xfrmi dev without taking device reference. Is it safe to directly access the new dev from skb in the subsequent async resumption? Will this trigger the issue again mentioned in 1c428b038400 ("xfrm: hold dev ref until after transport_finish NF_HOOK")? It seems that it is difficult to protect new skb->dev within the xfrm_input process. Best regards Dong Chenchen ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH net] xfrm: Fix dev use-after-free in xfrm async resumption 2026-06-01 12:17 ` dongchenchen (A) @ 2026-06-02 7:38 ` dongchenchen (A) 2026-06-09 6:14 ` Steffen Klassert 0 siblings, 1 reply; 5+ messages in thread From: dongchenchen (A) @ 2026-06-02 7:38 UTC (permalink / raw) To: Steffen Klassert Cc: herbert, davem, edumazet, kuba, pabeni, horms, tpluszz77, netdev, zhangchangzhong, xuchunxiao3 >> On Fri, May 29, 2026 at 05:21:11PM +0800, Dong Chenchen wrote: >>> xfrm async resumption hold skb->dev refcnt until after transport_finish. >>> However, xfrm_rcv_cb may modify skb->dev to tunnel dev without taking >>> device reference, such as vti_rcv_cb. The subsequent async resumption >>> will decrement the tunnel device's reference count, which lead to uaf >>> of tunnel dev and refcnt leak of orig dev as below: >>> >>> unregister_netdevice: waiting for vti1 to become free. Usage count = -2 >>> >>> Release refcnt of the original dev after tunnel rcv modify skb->dev to >>> fix it. >>> >>> Fixes: 1c428b038400 ("xfrm: hold dev ref until after transport_finish >>> NF_HOOK") >>> Reported-by: Xu Chunxiao <xuchunxiao3@huawei.com> >>> Signed-off-by: Dong Chenchen <dongchenchen2@huawei.com> >>> --- >>> net/xfrm/xfrm_input.c | 5 +++++ >>> 1 file changed, 5 insertions(+) >>> >>> diff --git a/net/xfrm/xfrm_input.c b/net/xfrm/xfrm_input.c >>> index f65291eba1f6..c979872b6006 100644 >>> --- a/net/xfrm/xfrm_input.c >>> +++ b/net/xfrm/xfrm_input.c >>> @@ -467,6 +467,7 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, >>> __be32 spi, int encap_type) >>> { >>> const struct xfrm_state_afinfo *afinfo; >>> struct net *net = dev_net(skb->dev); >>> + struct net_device *dev = skb->dev; >>> int err; >>> __be32 seq; >>> __be32 seq_hi; >>> @@ -730,6 +731,10 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, >>> __be32 spi, int encap_type) >>> if (err) >>> goto drop; >>> + if (async && skb->dev != dev) { >>> + dev_put(dev); >>> + async = 0; >>> + } >>> nf_reset_ct(skb); >>> if (decaps) { >> Sashiko found issues with this patch: >> >> https://netdev-ai.bots.linux.dev/sashiko/#/ >> patchset/20260529092111.1089315-1-dongchenchen2%40huawei.com >> >> Please review! >> > > Hi, Steffen! Thanks a lot for your review. > > This patch indeed cannot fix all the issues in the branches. > Maybe we can stash original skb->dev and move dev_put in > transport_finish to xfrm_input to fix it. > But there is a question, xfrm_rcv_cb modify skb->dev to tunnel or > xfrmi dev without taking device reference. Is it safe to directly > access the new dev from skb in the subsequent async resumption? > Will this trigger the issue again mentioned in 1c428b038400 ("xfrm: > hold dev ref until after transport_finish NF_HOOK")? It seems that > it is difficult to protect new skb->dev within the xfrm_input process. > > Best regards > Dong Chenchen > > Maybe we can fix it as bellow: Stash the original dev to fix refcnt imbalance. Add rcu protection for new skb->dev set by xfrm_rcv_cb to fix potential race with device teardown. diff --git a/net/ipv4/xfrm4_input.c b/net/ipv4/xfrm4_input.c index c2eac844bcdb..f6f2a8ef3f88 100644 --- a/net/ipv4/xfrm4_input.c +++ b/net/ipv4/xfrm4_input.c @@ -76,8 +76,6 @@ int xfrm4_transport_finish(struct sk_buff *skb, int async) NF_HOOK(NFPROTO_IPV4, NF_INET_PRE_ROUTING, dev_net(dev), NULL, skb, dev, NULL, xfrm4_rcv_encap_finish); - if (async) - dev_put(dev); return 0; } diff --git a/net/ipv6/xfrm6_input.c b/net/ipv6/xfrm6_input.c index 699a001ac166..89d0443b5307 100644 --- a/net/ipv6/xfrm6_input.c +++ b/net/ipv6/xfrm6_input.c @@ -71,8 +71,6 @@ int xfrm6_transport_finish(struct sk_buff *skb, int async) NF_HOOK(NFPROTO_IPV6, NF_INET_PRE_ROUTING, dev_net(dev), NULL, skb, dev, NULL, xfrm6_transport_finish2); - if (async) - dev_put(dev); return 0; } diff --git a/net/xfrm/xfrm_input.c b/net/xfrm/xfrm_input.c index f65291eba1f6..c9b82519fc04 100644 --- a/net/xfrm/xfrm_input.c +++ b/net/xfrm/xfrm_input.c @@ -467,6 +467,7 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type) { const struct xfrm_state_afinfo *afinfo; struct net *net = dev_net(skb->dev); + struct net_device *dev = skb->dev; int err; __be32 seq; __be32 seq_hi; @@ -493,7 +494,7 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type) LINUX_MIB_XFRMINSTATEINVALID); if (encap_type == -1) - dev_put(skb->dev); + dev_put(dev); goto drop; } @@ -660,7 +661,7 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type) nexthdr = x->type->input(x, skb); if (nexthdr == -EINPROGRESS) { if (async) - dev_put(skb->dev); + dev_put(dev); return 0; } @@ -699,7 +700,7 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type) err = xfrm_inner_mode_input(x, skb); if (err == -EINPROGRESS) { if (async) - dev_put(skb->dev); + dev_put(dev); return 0; } else if (err) { XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATEMODEERROR); @@ -726,10 +727,12 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type) crypto_done = false; } while (!err); + rcu_read_lock(); err = xfrm_rcv_cb(skb, family, x->type->proto, 0); - if (err) + if (err) { + rcu_read_unlock(); goto drop; - + } nf_reset_ct(skb); if (decaps) { @@ -739,8 +742,9 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type) if (skb_valid_dst(skb)) skb_dst_drop(skb); if (async) - dev_put(skb->dev); + dev_put(dev); gro_cells_receive(&gro_cells, skb); + rcu_read_unlock(); return 0; } else { xo = xfrm_offload(skb); @@ -748,23 +752,22 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type) xfrm_gro = xo->flags & XFRM_GRO; err = -EAFNOSUPPORT; - rcu_read_lock(); afinfo = xfrm_state_afinfo_get_rcu(x->props.family); if (likely(afinfo)) err = afinfo->transport_finish(skb, xfrm_gro || async); - rcu_read_unlock(); + if (xfrm_gro) { sp = skb_sec_path(skb); if (sp) sp->olen = 0; if (skb_valid_dst(skb)) if (skb_valid_dst(skb)) skb_dst_drop(skb); - if (async) - dev_put(skb->dev); gro_cells_receive(&gro_cells, skb); - return err; } + if (async) + dev_put(dev); + rcu_read_unlock(); return err; } @@ -772,7 +775,7 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type) spin_unlock(&x->lock); drop: if (async) - dev_put(skb->dev); + dev_put(dev); xfrm_rcv_cb(skb, family, x && x->type ? x->type->proto : nexthdr, -1); kfree_skb(skb); return 0;> ^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH net] xfrm: Fix dev use-after-free in xfrm async resumption 2026-06-02 7:38 ` dongchenchen (A) @ 2026-06-09 6:14 ` Steffen Klassert 0 siblings, 0 replies; 5+ messages in thread From: Steffen Klassert @ 2026-06-09 6:14 UTC (permalink / raw) To: dongchenchen (A) Cc: herbert, davem, edumazet, kuba, pabeni, horms, tpluszz77, netdev, zhangchangzhong, xuchunxiao3 On Tue, Jun 02, 2026 at 03:38:29PM +0800, dongchenchen (A) wrote: > > Maybe we can fix it as bellow: > Stash the original dev to fix refcnt imbalance. Add rcu protection > for new skb->dev set by xfrm_rcv_cb to fix potential race with device > teardown. Please submit the patch. In case we find issues then, you can just do another version. ^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2026-06-09 6:14 UTC | newest] Thread overview: 5+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-05-29 9:21 [PATCH net] xfrm: Fix dev use-after-free in xfrm async resumption Dong Chenchen 2026-06-01 6:32 ` Steffen Klassert 2026-06-01 12:17 ` dongchenchen (A) 2026-06-02 7:38 ` dongchenchen (A) 2026-06-09 6:14 ` Steffen Klassert
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox