summaryrefslogtreecommitdiff
path: root/include
diff options
context:
space:
mode:
authorCen Zhang <zzzccc427@gmail.com>2026-06-27 11:50:58 +0800
committerSteffen Klassert <steffen.klassert@secunet.com>2026-07-02 09:12:58 +0200
commitc4a5f0071cc6d378a0e7151b60d85986aefac1f3 (patch)
treee390db998401d026e5a4bfb147a8e97ff422724b /include
parentc283e9ada7fcb7dd4b10592623086b2e6d2f9925 (diff)
xfrm: cache the offload ifindex for netlink dumps
copy_to_user_state_extra() only holds a reference to the outer xfrm_state. That does not pin x->xso.dev. NETDEV_DOWN and NETDEV_UNREGISTER can race through xfrm_dev_state_flush(), xfrm_state_delete(), and xfrm_dev_state_free(), which clears xso->dev and drops the netdev reference before the GETSA dump reaches xso_to_xuo() and reads xso->dev->ifindex. The buggy scenario involves two paths, with each column showing the order within that path: XFRM_MSG_GETSA dump path: NETDEV teardown path: 1. xfrm_get_sa() gets xfrm_state 1. xfrm_dev_state_flush() finds x 2. copy_to_user_state_extra() sees 2. xfrm_state_delete() removes x x->xso.dev from the SAD 3. copy_user_offload() calls 3. xfrm_dev_state_free() clears xso_to_xuo() xso->dev 4. xso->dev->ifindex dereferences 4. netdev_put() drops the device a detached net_device reference Avoid following the live net_device from the dump paths. Cache the attached ifindex in xfrm_dev_offload when state or policy offload is bound to a device, and serialize that snapshot instead. This preserves the user-visible XFRMA_OFFLOAD_DEV value without depending on the embedded net_device lifetime. Validation reproduced this kernel report: Oops: general protection fault Call Trace: <TASK> copy_to_user_state_extra+0xb8d/0x1370 [xfrm_user] ? __pfx_copy_to_user_state_extra+0x10/0x10 [xfrm_user] ? __asan_memset+0x23/0x50 ? srso_alias_return_thunk+0x5/0xfbef5 ? __alloc_skb+0x342/0x960 ? srso_alias_return_thunk+0x5/0xfbef5 ? __asan_memset+0x23/0x50 ? srso_alias_return_thunk+0x5/0xfbef5 ? __nlmsg_put+0x147/0x1b0 dump_one_state+0x1c7/0x3e0 [xfrm_user] xfrm_state_netlink+0xcb/0x130 [xfrm_user] ? __pfx_xfrm_state_netlink+0x10/0x10 [xfrm_user] ? srso_alias_return_thunk+0x5/0xfbef5 ? xfrm_user_state_lookup.constprop.0+0x230/0x310 [xfrm_user] xfrm_get_sa+0x102/0x250 [xfrm_user] ? __pfx_xfrm_get_sa+0x10/0x10 [xfrm_user] xfrm_user_rcv_msg+0x504/0xaa0 [xfrm_user] ? __pfx_xfrm_user_rcv_msg+0x10/0x10 [xfrm_user] ? srso_alias_return_thunk+0x5/0xfbef5 ? stack_trace_save+0x8e/0xc0 ? __pfx_stack_trace_save+0x10/0x10 netlink_rcv_skb+0x11f/0x350 ? __pfx_xfrm_user_rcv_msg+0x10/0x10 [xfrm_user] ? __pfx_netlink_rcv_skb+0x10/0x10 ? __pfx_mutex_lock+0x10/0x10 ? srso_alias_return_thunk+0x5/0xfbef5 xfrm_netlink_rcv+0x65/0x80 [xfrm_user] netlink_unicast+0x600/0x870 ? __pfx_netlink_unicast+0x10/0x10 ? srso_alias_return_thunk+0x5/0xfbef5 ? __pfx_stack_trace_save+0x10/0x10 netlink_sendmsg+0x75d/0xc10 ? __pfx_netlink_sendmsg+0x10/0x10 ? srso_alias_return_thunk+0x5/0xfbef5 ____sys_sendmsg+0x77a/0x900 ? srso_alias_return_thunk+0x5/0xfbef5 ? __pfx_____sys_sendmsg+0x10/0x10 ? __pfx_copy_msghdr_from_user+0x10/0x10 ? release_sock+0x1a/0x1d0 ? srso_alias_return_thunk+0x5/0xfbef5 ? netlink_insert+0x143/0xec0 ___sys_sendmsg+0xff/0x180 ? __pfx____sys_sendmsg+0x10/0x10 ? _raw_spin_lock_irqsave+0x85/0xe0 ? do_getsockname+0xf9/0x170 ? srso_alias_return_thunk+0x5/0xfbef5 ? fdget+0x53/0x3b0 __sys_sendmsg+0x111/0x1a0 ? __pfx___sys_sendmsg+0x10/0x10 ? srso_alias_return_thunk+0x5/0xfbef5 ? __sys_getsockname+0x8c/0x100 do_syscall_64+0x102/0x5a0 entry_SYSCALL_64_after_hwframe+0x77/0x7f Fixes: 07b87f9eea0c ("xfrm: Fix unregister netdevice hang on hardware offload.") Assisted-by: Codex:gpt-5.5 Signed-off-by: Cen Zhang <zzzccc427@gmail.com> Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
Diffstat (limited to 'include')
-rw-r--r--include/net/xfrm.h2
1 files changed, 2 insertions, 0 deletions
diff --git a/include/net/xfrm.h b/include/net/xfrm.h
index 519a0156a05c..a6d69aaa6cd2 100644
--- a/include/net/xfrm.h
+++ b/include/net/xfrm.h
@@ -162,6 +162,8 @@ struct xfrm_dev_offload {
*/
struct net_device *real_dev;
unsigned long offload_handle;
+ /* Snapshot the attached device index for dump paths. */
+ int ifindex;
u8 dir : 2;
u8 type : 2;
u8 flags : 2;