* [PATCH net 0/2] vti: fix tunnel device use-after-free across async crypto resumption
@ 2026-09-30 9:08 Qihang
2026-09-30 9:08 ` [PATCH net 1/2] " Qihang
` (2 more replies)
0 siblings, 3 replies; 7+ messages in thread
From: Qihang @ 2026-09-30 9:08 UTC (permalink / raw)
To: netdev; +Cc: steffen.klassert, herbert
vti_input() and vti6_input_proto() cache the tunnel pointer in the skb
control buffer without taking a reference. With async crypto the
receive callback runs from the crypto completion, so a concurrent
RTM_DELLINK can free the tunnel device before the callback uses the
cached pointer. The existing rcu_read_lock() around the callback does
not protect it.
Patch 1 fixes the IPv4 side and carries the full description; patch 2
applies the same fix to the IPv6 side.
Qihang (2):
vti: fix tunnel device use-after-free across async crypto resumption
vti6: fix tunnel device use-after-free across async crypto resumption
net/ipv4/ip_vti.c | 7 +++++++
net/ipv6/ip6_vti.c | 8 ++++++++
2 files changed, 15 insertions(+)
--
2.54.0 (Apple Git-157)
^ permalink raw reply [flat|nested] 7+ messages in thread* [PATCH net 1/2] vti: fix tunnel device use-after-free across async crypto resumption 2026-09-30 9:08 [PATCH net 0/2] vti: fix tunnel device use-after-free across async crypto resumption Qihang @ 2026-09-30 9:08 ` Qihang 2026-10-04 10:08 ` netdev-bot+sashiko 2026-09-30 9:08 ` [PATCH net 2/2] vti6: " Qihang 2026-09-30 9:13 ` [PATCH net 0/2] vti: " netdev-bot+sinfo 2 siblings, 1 reply; 7+ messages in thread From: Qihang @ 2026-09-30 9:08 UTC (permalink / raw) To: netdev; +Cc: steffen.klassert, herbert vti_input() caches the tunnel pointer in the skb control buffer without taking a device reference. With async crypto, vti_rcv_cb() runs from the crypto completion, after a possible device teardown, and dereferences the freed tunnel device. The rcu_read_lock() around the callback cannot protect it, as the pointer was cached before the deletion grace period. Take a device reference while the pointer is cached and drop it in vti_rcv_cb() after the last use. An RTM_DELLINK on a VTI device with pending async crypto now waits for the completion. Fixes: df3893c176e9 ("vti: Update the ipv4 side to use it's own receive hook.") Cc: stable@vger.kernel.org Signed-off-by: Qihang <q.h.hack.winter@gmail.com> --- net/ipv4/ip_vti.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/net/ipv4/ip_vti.c b/net/ipv4/ip_vti.c index 3b80929994a0..9f44666139f8 100644 --- a/net/ipv4/ip_vti.c +++ b/net/ipv4/ip_vti.c @@ -63,6 +63,8 @@ static int vti_input(struct sk_buff *skb, int nexthdr, __be32 spi, XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip4 = tunnel; + dev_hold(tunnel->dev); + if (update_skb_dev) skb->dev = tunnel->dev; @@ -109,10 +111,14 @@ static int vti_rcv_cb(struct sk_buff *skb, int err) dev = tunnel->dev; + /* Drop the reference taken in vti_input(). -EINVAL/-EPERM make + * xfrm_input() re-invoke us with err = -1 and drop it then. + */ if (err) { DEV_STATS_INC(dev, rx_errors); DEV_STATS_INC(dev, rx_dropped); + dev_put(dev); return 0; } @@ -141,6 +147,7 @@ static int vti_rcv_cb(struct sk_buff *skb, int err) skb_scrub_packet(skb, !net_eq(tunnel->net, dev_net(skb->dev))); skb->dev = dev; dev_sw_netstats_rx_add(dev, skb->len); + dev_put(dev); return 0; } -- 2.54.0 (Apple Git-157) ^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH net 1/2] vti: fix tunnel device use-after-free across async crypto resumption 2026-09-30 9:08 ` [PATCH net 1/2] " Qihang @ 2026-10-04 10:08 ` netdev-bot+sashiko 2026-10-08 1:49 ` Qihang 0 siblings, 1 reply; 7+ messages in thread From: netdev-bot+sashiko @ 2026-10-04 10:08 UTC (permalink / raw) To: q.h.hack.winter; +Cc: netdev, steffen.klassert, herbert, kuba Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider. Critical: 0 · High: 3 · Medium: 0 · Low: 0 (1) If you believe none of the issues are legitimate, please reply to each issue of Medium severity or higher and explain why the AI is wrong. If any of them are legitimate and you plan to respin, please let patchwork know by including "pw-bot: cr" as a separate line at the end of your reply (one such reply per series is enough). - [High] Leaked net_device reference when a VTI tunnel uses an IPTFS SA. - [High] vti_rcv_cb() drops the only reference that keeps the VTI device alive before its caller has finished using it. - [High] The dev_hold() added in vti_input() (net/ipv4/ip_vti.c:66) leaks when xfrm_input() drops the skb through the early invalid-state check. Pre-existing issues: - [Low] Concern: the IPv6 VTI driver has the same unreferenced cached- tunnel pattern and this patch does not fix it. -- vti: fix tunnel device use-after-free across async crypto resumption This patch takes a reference on the VTI tunnel device in vti_input() when the tunnel pointer is cached in the skb control buffer. It drops that reference in vti_rcv_cb() on both the error and success paths, so the device stays alive across async crypto completion. > diff --git a/net/ipv4/ip_vti.c b/net/ipv4/ip_vti.c > index 3b80929994a00..9f44666139f8c 100644 > --- a/net/ipv4/ip_vti.c > +++ b/net/ipv4/ip_vti.c > @@ -63,6 +63,8 @@ static int vti_input(struct sk_buff *skb, int nexthdr, __be32 spi, > > XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip4 = tunnel; > > + dev_hold(tunnel->dev); > + [Severity: High] Can this reference leak when the matching SA uses IPTFS mode? The only matching dev_put() calls are in vti_rcv_cb(). That means this relies on xfrm_input() calling the callback exactly once per skb. For an IPTFS SA, xfrm_input() dispatches to iptfs_input(), which always returns -EINPROGRESS: net/xfrm/xfrm_input.c:xfrm_input() { ... err = xfrm_inner_mode_input(x, skb); if (err == -EINPROGRESS) { if (async) dev_put(dev); return 0; } ... } That return skips xfrm_rcv_cb(). Only the outer skb has tunnel.ip4 in its cb. It comes back into vti_rcv_cb() through xfrm_input(skb, 0, 0, -2) only when __input_process_payload() reuses it as a complete first inner packet. In these other cases the outer skb is freed without any callback: - consume_skb(defer) in __input_process_payload(), when the skb has a frag_list, is head_frag, or cannot be reused - kfree_skb(skb) in __input_process_payload() when there is no first_skb (padding-only or continuation-only outer packets) - kfree_skb(skb) in iptfs_input_ordered() when IPTFS header validation fails - the reorder window freelist in iptfs_input() - the reassembly drop timer and state teardown that free ra_newskb iptfs_alloc_skb() builds inner skbs with alloc_skb(), so their cb is zeroed and tunnel.ip4 is NULL. For those skbs vti_rcv_cb() returns 1, so they can't make up the missing dev_put(). IPTFS is a tunnel mode, so it passes xfrm_tunnel_check() on a VTI device. Once such an SA is configured, would normal traffic from the peer leak one VTI device reference per packet? If so, ip link del or netns teardown would block forever in netdev_wait_allrefs_any() with "waiting for vtiX to become free". This path did not leak before this patch. The follow-up commit "vti6: fix tunnel device use-after-free across async crypto resumption" takes the same unconditional hold in vti6_input_proto(), so ip6_vti looks like it has the same leak. [Severity: Low] This is a pre-existing issue, not one introduced by this patch. vti6_input_proto() in net/ipv6/ip6_vti.c also caches t in XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip6 without taking a device reference. vti6_rcv_cb() may later dereference t->dev, t->parms.i_key and t->net from an async crypto completion. The next patch in the series, "vti6: fix tunnel device use-after-free across async crypto resumption", adds dev_hold(t->dev) in vti6_input_proto() and matching dev_put() calls in vti6_rcv_cb(). That fixes the IPv6 side. It also inherits the leak and early-release questions raised here for IPv4. Is the IPv6 side meant to be handled only by that follow-up? > if (update_skb_dev) > skb->dev = tunnel->dev; > [ ... ] > @@ -109,10 +111,14 @@ static int vti_rcv_cb(struct sk_buff *skb, int err) > > dev = tunnel->dev; > > + /* Drop the reference taken in vti_input(). -EINVAL/-EPERM make > + * xfrm_input() re-invoke us with err = -1 and drop it then. > + */ [Severity: High] Does every drop in xfrm_input() actually call back here with err = -1? In xfrm_input(), the early invalid-state check jumps to drop before family is set: net/xfrm/xfrm_input.c:xfrm_input() { unsigned int family = AF_UNSPEC; ... if (unlikely(x->km.state != XFRM_STATE_VALID)) { ... if (encap_type == -1) dev_put(dev); goto drop; } family = x->props.family; ... drop: if (async) dev_put(dev); xfrm_rcv_cb(skb, family, xfrm_proto, -1); kfree_skb(skb); return 0; } With family == AF_UNSPEC, xfrm_rcv_cb() looks up xfrm_input_afinfo[is_ipip][0]. Nothing is registered at that index, since only AF_INET and AF_INET6 register. So it returns without ever calling vti_rcv_cb(): afinfo = xfrm_input_get_afinfo(family, is_ipip); if (!afinfo) return -EAFNOSUPPORT; The skb is then freed, and the reference taken in vti_input() is never dropped. This path can be reached in three ways: - async resume (encap_type == -1) when the SA was deleted or expired while decryption was in flight, e.g. ip xfrm state flush or an IKE rekey under traffic with an async crypto driver - the hardware offload entry (encap_type == 0) with a non-valid SA - IPTFS re-injection (encap_type == -2) with a non-valid SA Would the VTI device then wait forever in netdev_wait_allrefs_any() on unregister? The vti6 follow-up commit adds the same hold in vti6_input_proto(), so it looks exposed as well. > if (err) { > DEV_STATS_INC(dev, rx_errors); > DEV_STATS_INC(dev, rx_dropped); > > + dev_put(dev); > return 0; > } > > @@ -141,6 +147,7 @@ static int vti_rcv_cb(struct sk_buff *skb, int err) > skb_scrub_packet(skb, !net_eq(tunnel->net, dev_net(skb->dev))); > skb->dev = dev; > dev_sw_netstats_rx_add(dev, skb->len); > + dev_put(dev); [Severity: High] Is this really after the last use of dev? The commit message says the reference is dropped "after the last use". However, skb->dev was just set to the VTI device, and xfrm_input() keeps using it after this returns 0: net/xfrm/xfrm_input.c:xfrm_input() { ... err = xfrm_rcv_cb(skb, family, xfrm_proto, 0); ... nf_reset_ct(skb); if (decaps) { ... if (async) dev_put(dev); gro_cells_receive(&gro_cells, skb); ... } xfrm_tunnel_check() forces tunnel mode for VTI, so decaps is set. gro_cells_receive() reads skb->dev->flags. On the !IFF_UP drop path it calls dev_core_stats_rx_dropped_inc(dev), which can allocate and cmpxchg into dev->core_stats. Here is the race, with an async ESP decrypt pending on the VTI device: CPU1 (ip link del vtiX) unregister clears IFF_UP netdev_run_todo() netdev_wait_allrefs_any() polling, the async skb holds a ref CPU2 (crypto completion) xfrm_input_resume() xfrm_input(skb, ..., -1) xfrm_rcv_cb() vti_rcv_cb() dev_put(dev) refcnt drops to 1 CPU1 netdev_wait_allrefs_any() returns dev netdev_do_free_pcpu_stats(dev) dev->priv_destructor(dev) free_netdev(dev) CPU2 gro_cells_receive(&gro_cells, skb) reads skb->dev->flags on the freed device netdev_run_todo() has no RCU grace period between the refcount check and the free, so the rcu_read_lock() in xfrm_input() gives no protection here. Can this still reach the use-after-free the patch is meant to fix, just in a smaller window? The xfrm core does the same "if (async) dev_put(dev)" for the lower device right before gro_cells_receive(). That shows the pattern is shared, but not that it is safe. Would the reference need to be held until after gro_cells_receive() or transport_finish()? The vti6 follow-up commit repeats the same early dev_put() in vti6_rcv_cb(). > > return 0; > } -- Sashiko AI review · https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20260930090813.73901-1-q.h.hack.winter%40gmail.com ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH net 1/2] vti: fix tunnel device use-after-free across async crypto resumption 2026-10-04 10:08 ` netdev-bot+sashiko @ 2026-10-08 1:49 ` Qihang 0 siblings, 0 replies; 7+ messages in thread From: Qihang @ 2026-10-08 1:49 UTC (permalink / raw) To: netdev Cc: David Ahern, Ido Schimmel, Steffen Klassert, Herbert Xu, David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni, Simon Horman, linux-kernel All real, and vti6 has the same problems. The dev_hold()/dev_put() idea assumed the callback runs exactly once per skb, which xfrm_input() doesn't guarantee. IPTFS frees the outer skb on its own without any callback. The early drop when the SA is no longer valid happens while family is still AF_UNSPEC, so xfrm_rcv_cb() can't find the afinfo and never calls us. And on the success path I'd drop the last reference before gro_cells_receive() is done with skb->dev. So I'll drop this. Two options I can see for the respin: Re-lookup the tunnel in the callback like xfrmi does. The only key I have there is the outer addresses of the state, which won't reproduce the original lookup for wildcard-source SAs, and during teardown it can pick up the fallback device instead. The RCU section also ends at gro_cells_receive(): the skb queued to the gro cell is processed by NAPI afterwards with skb->dev still pointing at the tunnel device and nothing holding a reference. Keep a reference from vti_input() but release it when the skb is freed instead of in the callback, so the paths where the callback never runs can't leak. That looks like it needs xfrm core support, so I'd rather not pick it unilaterally. Which way do you want this to go? pw-bot: cr ^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH net 2/2] vti6: fix tunnel device use-after-free across async crypto resumption 2026-09-30 9:08 [PATCH net 0/2] vti: fix tunnel device use-after-free across async crypto resumption Qihang 2026-09-30 9:08 ` [PATCH net 1/2] " Qihang @ 2026-09-30 9:08 ` Qihang 2026-10-04 10:08 ` netdev-bot+sashiko 2026-09-30 9:13 ` [PATCH net 0/2] vti: " netdev-bot+sinfo 2 siblings, 1 reply; 7+ messages in thread From: Qihang @ 2026-09-30 9:08 UTC (permalink / raw) To: netdev; +Cc: steffen.klassert, herbert Same issue as on the IPv4 side: vti6_input_proto() caches the tunnel pointer without taking a device reference, and vti6_rcv_cb() runs from the async crypto completion, after a possible device teardown. Take a device reference while the pointer is cached and drop it in vti6_rcv_cb() after the last use, like the IPv4 side. Fixes: fa9ad96d4905 ("vti6: Update the ipv6 side to use its own receive hook.") Cc: stable@vger.kernel.org Signed-off-by: Qihang <q.h.hack.winter@gmail.com> --- net/ipv6/ip6_vti.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/net/ipv6/ip6_vti.c b/net/ipv6/ip6_vti.c index ab94b3a4ba9c..b53830d5cf54 100644 --- a/net/ipv6/ip6_vti.c +++ b/net/ipv6/ip6_vti.c @@ -322,6 +322,9 @@ static int vti6_input_proto(struct sk_buff *skb, int nexthdr, __be32 spi, rcu_read_unlock(); XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip6 = t; + + dev_hold(t->dev); + XFRM_SPI_SKB_CB(skb)->family = AF_INET6; XFRM_SPI_SKB_CB(skb)->daddroff = offsetof(struct ipv6hdr, daddr); return xfrm_input(skb, nexthdr, spi, encap_type); @@ -355,10 +358,14 @@ static int vti6_rcv_cb(struct sk_buff *skb, int err) dev = t->dev; + /* Drop the reference taken in vti6_input_proto(). -EINVAL/-EPERM + * make xfrm_input() re-invoke us with err = -1 and drop it then. + */ if (err) { DEV_STATS_INC(dev, rx_errors); DEV_STATS_INC(dev, rx_dropped); + dev_put(dev); return 0; } @@ -387,6 +394,7 @@ static int vti6_rcv_cb(struct sk_buff *skb, int err) skb_scrub_packet(skb, !net_eq(t->net, dev_net(skb->dev))); skb->dev = dev; dev_sw_netstats_rx_add(dev, skb->len); + dev_put(dev); return 0; } -- 2.54.0 (Apple Git-157) ^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH net 2/2] vti6: fix tunnel device use-after-free across async crypto resumption 2026-09-30 9:08 ` [PATCH net 2/2] vti6: " Qihang @ 2026-10-04 10:08 ` netdev-bot+sashiko 0 siblings, 0 replies; 7+ messages in thread From: netdev-bot+sashiko @ 2026-10-04 10:08 UTC (permalink / raw) To: q.h.hack.winter; +Cc: netdev, steffen.klassert, herbert, kuba Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider. Critical: 0 · High: 3 · Medium: 1 · Low: 0 If you believe none of the issues are legitimate, please reply to each issue of Medium severity or higher and explain why the AI is wrong. If any of them are legitimate and you plan to respin, please let patchwork know by including "pw-bot: cr" as a separate line at the end of your reply (one such reply per series is enough). - [High] This patch leaks the new ip6_vti device reference whenever an async-resumed (or HW-offloaded) packet hits an SA that is no longer… - [High] On a vti6 tunnel whose SA uses IP-TFS mode, the new dev_hold() leaks for every outer packet that IP-TFS frees instead of reinjecting. - [High] vti6_rcv_cb() sets skb->dev to the vti6 device (line 395) and then calls dev_put(dev) (line 397). - [Medium] Unloading the module can hang forever if the fallback ip6_vti0 device still has an async receive in flight. -- vti6: fix tunnel device use-after-free across async crypto resumption When vti6_input_proto() caches the tunnel pointer in the skb cb, this commit now takes a reference on the vti6 tunnel device. vti6_rcv_cb() drops that reference on both its error path and its success path. The change mirrors the equivalent IPv4 vti fix. > diff --git a/net/ipv6/ip6_vti.c b/net/ipv6/ip6_vti.c > index ab94b3a4ba9c3..b53830d5cf54b 100644 > --- a/net/ipv6/ip6_vti.c > +++ b/net/ipv6/ip6_vti.c > @@ -322,6 +322,9 @@ static int vti6_input_proto(struct sk_buff *skb, int nexthdr, __be32 spi, > rcu_read_unlock(); > > XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip6 = t; > + > + dev_hold(t->dev); > + [Severity: High] Can this reference leak when an async-resumed packet hits an SA that is no longer valid? The only dev_put() calls that match this dev_hold() are in vti6_rcv_cb(). xfrm_input() does not always reach the protocol callback chain. Suppose esp6_input() returns -EINPROGRESS, and the SA is deleted or expires before esp_input_done() calls xfrm_input_resume(). The resumed xfrm_input() call then takes the early branch: net/xfrm/xfrm_input.c:xfrm_input() { ... if (unlikely(x->km.state != XFRM_STATE_VALID)) { ... if (encap_type == -1) dev_put(dev); goto drop; } family = x->props.family; ... } At the drop label family is still AF_UNSPEC, so this runs: drop: if (async) dev_put(dev); xfrm_rcv_cb(skb, family, xfrm_proto, -1); kfree_skb(skb); Only AF_INET and AF_INET6 afinfo are ever registered, so xfrm_input_get_afinfo(AF_UNSPEC, is_ipip) returns NULL. xfrm_rcv_cb() then returns -EAFNOSUPPORT and never calls xfrm6_rcv_cb() or vti6_rcv_cb(). The offload path can hit the same early drop without any async crypto. Take an skb with xfrm_offload state, received with GRO disabled. It goes through vti6_rcv()->vti6_input_proto(..., 0) and takes the early branch because xo && encap_type == 0. Before this patch, skipping vti6_rcv_cb() here only lost a stats increment. With the new dev_hold(), would a later unregister of the ip6_vti device wait forever in netdev_wait_allrefs_any()? Deleting the old SA after an IKE rekey looks like a routine way to trigger this. The IPv4 patch in this series has the same gap in vti_input() and vti_rcv_cb(). [Severity: High] What happens to this reference when the SA on the vti6 tunnel uses IP-TFS mode? xfrm_tunnel_check() accepts IP-TFS SAs here, because the IPTFS entry in xfrm6_mode_map has XFRM_MODE_FLAG_TUNNEL set. After decryption, xfrm_inner_mode_input() calls x->mode_cbs->input(), which is iptfs_input(). That function always returns -EINPROGRESS. xfrm_input() then returns without calling xfrm_rcv_cb() for the outer skb: net/xfrm/xfrm_input.c:xfrm_input() { ... err = xfrm_inner_mode_input(x, skb); if (err == -EINPROGRESS) { if (async) dev_put(dev); return 0; ... } That dev_put() only drops the reference on the lower device. The outer skb carries tunnel.ip6 in its cb. It only gets back to vti6_rcv_cb() if IP-TFS reuses it as the first inner packet and reinjects it with xfrm_input(skb, 0, 0, -2). In several other cases IP-TFS frees it without any callback: - iptfs_input_ordered() on an invalid IP-TFS header (kfree_skb at done:) - __input_process_payload() on pad-only or continuation-only payloads (!first_skb leads to kfree_skb), and the defer consume_skb - the reorder-window freelist in iptfs_input() - expiry of the reassembly drop timer for ra_newskb Inner skbs from iptfs_alloc_skb() have a zeroed cb. vti6_rcv_cb() returns 1 for them without calling dev_put(). Would each of these outer packets leak one reference on the vti6 device? The peer controls the payload layout, and all-pad IP-TFS packets are normal traffic. The IPv4 patch has the same issue. [Severity: Medium] Can rmmod ip6_vti hang forever if the fallback ip6_vti0 device has an async receive in flight? vti6_tnl_lookup() can return the fallback tunnel while its device is up, so this dev_hold() can be taken on ip6_vti0. vti6_tunnel_cleanup() then runs: rtnl_link_unregister(&vti6_link_ops); ... xfrm6_protocol_deregister(&vti_ipcomp6_protocol, IPPROTO_COMP); xfrm6_protocol_deregister(&vti_ah6_protocol, IPPROTO_AH); xfrm6_protocol_deregister(&vti_esp6_protocol, IPPROTO_ESP); unregister_pernet_device(&vti6_net_ops); rtnl_link_unregister() does not drain ip6_vti0, because vti6_dellink() skips it: if (dev != ip6n->fb_tnl_dev) unregister_netdevice_queue(dev, head); Suppose the crypto completion runs after the xfrm6_protocol_deregister() calls. xfrm6_rcv_cb() only walks the handlers that are still registered, so vti6_rcv_cb() never runs and the reference is never dropped. Would unregister_pernet_device() then wait forever in netdev_wait_allrefs_any() for ip6_vti0, while holding pernet_ops_rwsem? [ ... ] > @@ -387,6 +394,7 @@ static int vti6_rcv_cb(struct sk_buff *skb, int err) > skb_scrub_packet(skb, !net_eq(t->net, dev_net(skb->dev))); > skb->dev = dev; > dev_sw_netstats_rx_add(dev, skb->len); > + dev_put(dev); [Severity: High] Is this reference dropped before the last use of the vti6 device? skb->dev has just been set to the vti6 device. After xfrm_rcv_cb() returns, xfrm_input() keeps using it in the decaps branch: net/xfrm/xfrm_input.c:xfrm_input() { ... if (async) dev_put(dev); gro_cells_receive(&gro_cells, skb); rcu_read_unlock(); ... } The dev_put() there only drops the reference on the original lower device. gro_cells_receive() then dereferences skb->dev: net/core/gro_cells.c:gro_cells_receive() { struct net_device *dev = skb->dev; ... if (unlikely(!(dev->flags & IFF_UP))) goto drop; ... drop: dev_core_stats_rx_dropped_inc(dev); ... } Consider an unregister that starts while crypto is pending. It has already cleared IFF_UP and finished its synchronize_net() calls, and is now polling in netdev_wait_allrefs_any(). Once this dev_put() brings the refcount to 1, netdev_run_todo() goes on to free the pcpu stats and the device with no further grace period. The rcu_read_lock() in xfrm_input() started after the unregister's grace periods, so it does not hold off that free. Could gro_cells_receive() then read dev->flags and write dev->core_stats on freed memory? The commit message says: Take a device reference while the pointer is cached and drop it in vti6_rcv_cb() after the last use, like the IPv4 side. The last use of the device is in xfrm_input(), after vti6_rcv_cb() has returned, so the use-after-free window seems narrower but still reachable. The IPv4 patch has the same ordering. > > return 0; > } -- Sashiko AI review · https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20260930090813.73901-1-q.h.hack.winter%40gmail.com ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH net 0/2] vti: fix tunnel device use-after-free across async crypto resumption 2026-09-30 9:08 [PATCH net 0/2] vti: fix tunnel device use-after-free across async crypto resumption Qihang 2026-09-30 9:08 ` [PATCH net 1/2] " Qihang 2026-09-30 9:08 ` [PATCH net 2/2] vti6: " Qihang @ 2026-09-30 9:13 ` netdev-bot+sinfo 2 siblings, 0 replies; 7+ messages in thread From: netdev-bot+sinfo @ 2026-09-30 9:13 UTC (permalink / raw) To: Qihang; +Cc: netdev, steffen.klassert, herbert Hi! This is an automated message. This series looks like a fix, but its commit messages seem to be missing some information: - How the issue was discovered, e.g. hit in production, hit during development, syzbot report, manual code inspection, LLM or static analysis tool scan. - Whether the issue was actually triggered, or is only theoretical (e.g. found by code inspection). If it was triggered please include the symptoms, like the stack trace or error messages. Please do not repost the series just to address the above. Instead, reply to this email with the missing information, so that reviewers can take it into account. If the series needs another revision for other reasons, please include the information in the commit messages then. The evaluation is done by an LLM so it may be wrong, if you think that is the case please reply and explain. ^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2026-10-08 1:49 UTC | newest] Thread overview: 7+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-09-30 9:08 [PATCH net 0/2] vti: fix tunnel device use-after-free across async crypto resumption Qihang 2026-09-30 9:08 ` [PATCH net 1/2] " Qihang 2026-10-04 10:08 ` netdev-bot+sashiko 2026-10-08 1:49 ` Qihang 2026-09-30 9:08 ` [PATCH net 2/2] vti6: " Qihang 2026-10-04 10:08 ` netdev-bot+sashiko 2026-09-30 9:13 ` [PATCH net 0/2] vti: " netdev-bot+sinfo
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox