[PATCH net v4 0/3] xfrm: fix vti tunnel device use-after-free across async crypto resumption

From: Qihang

Date: Sun Oct 18 2026 - 05:06:52 EST


This replaces the v1/v2 vti/vti6 series and the earlier reference-transfer
rework.

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, after a possible
device teardown, and dereferences the freed tunnel device.

The input hook takes a reference on the tunnel device when it caches
the tunnel. A successful receive callback leaves the cached tunnel in
place; xfrm_input() releases the reference on every exit, including
after delivery and on the drop paths. The error callback only updates
the counters, so the common drop path releases the reference after the
skb has been freed. IPTFS, which frees the outer skb itself, releases
it through xfrm_input_drop()/xfrm_input_consume().

Patch 3 depends on the first two: it releases the tunnel reference from
the drop path, which needs the receive callback ordering and the address
family set up by patches 1 and 2.

Changes since v3:
- the cached pointer is always a tunnel; the address family selects its
type, and a non-NULL slot means one device reference is held, so a
nested or pre-installed tunnel device cannot leak it
- xfrm_input() takes the device out of the skb before
gro_cells_receive()/transport_finish(), which may consume the skb
- the device reference is dropped only after the skb has been freed,
including on the error path
- IPTFS passes the state's address family explicitly instead of
inferring it from the secpath; the consumed skb keeps consume_skb()
semantics and the drop paths keep their skb drop reason
- drop the xfrmi changes: it re-looks-up the interface and does not
take part in the reference transfer
- merge the reference and IPTFS changes into one patch so the series
stays bisectable
- the gro_cells NAPI window is pre-existing and is documented, not
changed

Runtime evidence (KASAN, aarch64 QEMU):
- VTI async success and error: RTM_DELLINK completes without a KASAN
report; the unfixed tree reports slab-use-after-free in vti_rcv_cb.
- Async resume with the SA deleted in the crypto window: the reference
is released and the device is removed; with patch 2 reverted,
xfrm_input_take_tunnel_dev() warns and unregister_netdevice() waits
for vti0.
- IPTFS outer-skb free: RTM_DELLINK completes; with the !first_skb
xfrm_input_drop() reverted to kfree_skb(), the reference leaks and
unregister_netdevice() waits for vti0.
The IPTFS timer/reorder/state-teardown paths are covered by code audit,
not by a runtime trigger.

Previous versions:
https://lore.kernel.org/netdev/20261013074610.17808-1-q.h.hack.winter@xxxxxxxxx/ (v2)
https://lore.kernel.org/netdev/20260930090813.73901-1-q.h.hack.winter@xxxxxxxxx/ (v1)

Qihang


Qihang (3):
xfrm: run the receive callback before dropping the skb->dev reference
xfrm: set the address family before the early invalid-state drop
xfrm: hold the tunnel device reference across the input path

net/ipv4/ip_vti.c | 3 ++
net/ipv6/ip6_vti.c | 4 +++
net/ipv6/xfrm6_input.c | 3 ++
net/xfrm/xfrm_inout.h | 4 +++
net/xfrm/xfrm_input.c | 74 +++++++++++++++++++++++++++++++++++++++---
net/xfrm/xfrm_iptfs.c | 25 +++++++++-----
6 files changed, 99 insertions(+), 14 deletions(-)

--
2.54.0 (Apple Git-157)