Netdev List
 help / color / mirror / Atom feed
* [PATCH ipsec] xfrm: protect offload statistics device access with RCU
@ 2026-10-29  3:18 Cen Zhang
  0 siblings, 0 replies; only message in thread
From: Cen Zhang @ 2026-10-29  3:18 UTC (permalink / raw)
  To: steffen.klassert, herbert
  Cc: davem, netdev, baijiaju1990, jjzuming, zzzccc427

The offload device must remain alive while copy_to_user_state() reads
its operation table through xfrm_dev_state_update_stats(). GETSA holds
a reference to the xfrm_state, but device teardown can release the
state's device reference before that state reference is dropped.

With an offloaded SA, GETSA can sample xso.dev while another task takes
the device down and unregisters it. For example, deleting a netdevsim
port through sysfs can overlap a GETSA request for an accepted crypto
offload SA. The XFRM configuration mutex does not serialize the request
against the netdevice notifier:

  GETSA                              Device teardown
  -----                              ---------------
  look up and reference x
  copy_to_user_state(x)
    sample dev = x->xso.dev
                                     xfrm_dev_state_flush()
                                       xfrm_state_delete(x)
                                       xfrm_dev_state_free(x)
                                         clear x->xso.dev
                                         put device reference
                                     synchronize_net()
                                     finish unregister and free dev
    read dev->xfrmdev_ops

The sampled pointer does not hold a device reference or participate in
the unregister grace period, so the last read can access freed memory.

Wrap the serializer's statistics update in an RCU read-side critical
section. Device unregistration calls synchronize_net() after the XFRM
notifier has cleared the binding and before releasing the device. A
reader that sampled the old binding must therefore finish its device
access before final release; a later reader finds the cleared binding.
The helper already runs from atomic contexts, so this section does not
add a sleeping operation.

The report below was collected on an earlier kernel with a built-in
pmbdxfrm test endpoint supplying no-op offload add/delete callbacks.
Scheduling probes paused GETSA after sampling the device, then ran
normal link-down and link-delete requests before resuming the read.

KASAN report as below:

    BUG: KASAN: slab-use-after-free in copy_to_user_state+0x6ce/0x6e0
    Read of size 8 at addr ffff888104be0308 by task ip/446
    
    CPU: 3 UID: 0 PID: 446 Comm: ip Not tainted 7.2.0-rc5-pmb-xfrm-functional-v1+ #3 PREEMPT(lazy) 
    Hardware name: QEMU Ubuntu 24.04 PC v2 (i440FX + PIIX, arch_caps fix, 1996), BIOS 1.16.3-debian-1.16.3-2 04/01/2014
    Call Trace:
     <TASK>
     dump_stack_lvl+0x93/0xd0
     print_report+0xce/0x630
     ? copy_to_user_state+0x6ce/0x6e0
     ? srso_alias_return_thunk+0x5/0xfbef5
     ? __virt_addr_valid+0x20d/0x410
     ? copy_to_user_state+0x6ce/0x6e0
     kasan_report+0xe0/0x110
     ? copy_to_user_state+0x6ce/0x6e0
     copy_to_user_state+0x6ce/0x6e0
     copy_to_user_state_extra+0x8a/0x1450
     ? __pfx_copy_to_user_state_extra+0x10/0x10
     ? srso_alias_return_thunk+0x5/0xfbef5
     ? __asan_memset+0x23/0x50
     ? srso_alias_return_thunk+0x5/0xfbef5
     ? srso_alias_return_thunk+0x5/0xfbef5
     ? __asan_memset+0x23/0x50
     ? srso_alias_return_thunk+0x5/0xfbef5
     ? __nlmsg_put+0x157/0x1c0
     dump_one_state+0x1fd/0x440
     xfrm_state_netlink+0xda/0x150
     ? __pfx_xfrm_state_netlink+0x10/0x10
     ? srso_alias_return_thunk+0x5/0xfbef5
     ? xfrm_user_state_lookup.constprop.0+0x28e/0x330
     xfrm_get_sa+0x12d/0x320
     ? __pfx_xfrm_get_sa+0x10/0x10
     ? srso_alias_return_thunk+0x5/0xfbef5
     ? __nla_parse+0x40/0x60
     ? __pfx_xfrm_get_sa+0x10/0x10
     xfrm_user_rcv_msg+0x3b3/0xc20
     ? __pfx_xfrm_user_rcv_msg+0x10/0x10
     ? srso_alias_return_thunk+0x5/0xfbef5
     ? stack_trace_save+0x93/0xd0
     ? __pfx_stack_trace_save+0x10/0x10
     ? srso_alias_return_thunk+0x5/0xfbef5
     ? stack_depot_save_flags+0x29/0x9a0
     ? srso_alias_return_thunk+0x5/0xfbef5
     ? __mutex_lock+0x182c/0x2590
     netlink_rcv_skb+0x133/0x390
     ? __netlink_lookup+0x5e4/0x7e0
     ? __pfx_xfrm_user_rcv_msg+0x10/0x10
     ? __pfx_netlink_rcv_skb+0x10/0x10
     ? srso_alias_return_thunk+0x5/0xfbef5
     ? netlink_deliver_tap+0xdf/0xbd0
     ? srso_alias_return_thunk+0x5/0xfbef5
     ? netlink_deliver_tap+0x173/0xbd0
     xfrm_netlink_rcv+0x76/0x90
     netlink_unicast+0x504/0x840
     ? __pfx_netlink_unicast+0x10/0x10
     netlink_sendmsg+0x7f7/0xcf0
     ? __pfx_netlink_sendmsg+0x10/0x10
     ? srso_alias_return_thunk+0x5/0xfbef5
     ? selinux_socket_sendmsg+0x160/0x280
     ? __pfx_netlink_sendmsg+0x10/0x10
     ____sys_sendmsg+0x88b/0x9d0
     ? __pfx_____sys_sendmsg+0x10/0x10
     ? srso_alias_return_thunk+0x5/0xfbef5
     ? __lock_acquire+0x466/0x2260
     ___sys_sendmsg+0x125/0x1d0
     ? __lock_acquire+0x466/0x2260
     ? __pfx____sys_sendmsg+0x10/0x10
     ? srso_alias_return_thunk+0x5/0xfbef5
     ? srso_alias_return_thunk+0x5/0xfbef5
     ? do_getsockname+0x130/0x1b0
     ? __pfx_do_getsockname+0x10/0x10
     __sys_sendmsg+0x13e/0x1e0
     ? __pfx___sys_sendmsg+0x10/0x10
     ? srso_alias_return_thunk+0x5/0xfbef5
     ? __sys_getsockname+0xbc/0x110
     do_syscall_64+0x115/0x6a0
     entry_SYSCALL_64_after_hwframe+0x77/0x7f
    RIP: 0033:0x7f74d2c0b687
    Code: 48 89 fa 4c 89 df e8 58 b3 00 00 8b 93 08 03 00 00 59 5e 48 83 f8 fc 74 1a 5b c3 0f 1f 84 00 00 00 00 00 48 8b 44 24 10 0f 05 <5b> c3 0f 1f 80 00 00 00 00 83 e2 39 83 fa 08 75 de e8 23 ff ff ff
    RSP: 002b:00007ffee6b82680 EFLAGS: 00000202 ORIG_RAX: 000000000000002e
    RAX: ffffffffffffffda RBX: 00007f74d29de840 RCX: 00007f74d2c0b687
    RDX: 0000000000000000 RSI: 00007ffee6b82730 RDI: 0000000000000004
    RBP: 00007ffee6b82730 R08: 0000000000000000 R09: 0000000000000000
    R10: 0000000000000000 R11: 0000000000000202 R12: 000055cc4cbea909
    R13: 00007ffee6b82870 R14: 00007ffee6b82800 R15: 00007ffee6b83e13
     </TASK>
    
    Allocated by task 420:
     kasan_save_stack+0x33/0x60
     kasan_save_track+0x14/0x30
     __kasan_kmalloc+0xaa/0xb0
     __kvmalloc_node_noprof+0x353/0x930
     alloc_netdev_mqs+0xa0/0x1250
     rtnl_create_link+0xb8e/0xeb0
     rtnl_newlink+0xb7b/0x1f40
     rtnetlink_rcv_msg+0x7b9/0xce0
     netlink_rcv_skb+0x133/0x390
     netlink_unicast+0x504/0x840
     netlink_sendmsg+0x7f7/0xcf0
     ____sys_sendmsg+0x88b/0x9d0
     ___sys_sendmsg+0x125/0x1d0
     __sys_sendmsg+0x13e/0x1e0
     do_syscall_64+0x115/0x6a0
     entry_SYSCALL_64_after_hwframe+0x77/0x7f
    
    Freed by task 451:
     kasan_save_stack+0x33/0x60
     kasan_save_track+0x14/0x30
     kasan_save_free_info+0x3b/0x60
     __kasan_slab_free+0x5f/0x80
     kfree+0x307/0x580
     device_release+0xd7/0x280
     kobject_put+0x1ad/0x610
     netdev_run_todo+0x927/0x13d0
     rtnl_dellink+0x3aa/0xa30
     rtnetlink_rcv_msg+0x7b9/0xce0
     netlink_rcv_skb+0x133/0x390
     netlink_unicast+0x504/0x840
     netlink_sendmsg+0x7f7/0xcf0
     ____sys_sendmsg+0x88b/0x9d0
     ___sys_sendmsg+0x125/0x1d0
     __sys_sendmsg+0x13e/0x1e0
     do_syscall_64+0x115/0x6a0
     entry_SYSCALL_64_after_hwframe+0x77/0x7f
    
    The buggy address belongs to the object at ffff888104be0000
     which belongs to the cache kmalloc-4k of size 4096
    The buggy address is located 776 bytes inside of
     freed 4096-byte region [ffff888104be0000, ffff888104be1000)
    
    The buggy address belongs to the physical page:
    page: refcount:0 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0x104be0
    head: order:3 mapcount:0 entire_mapcount:0 nr_pages_mapped:0 pincount:0
    flags: 0x200000000000040(head|node=0|zone=2)
    page_type: f5(slab)
    raw: 0200000000000040 ffff888100043040 dead000000000122 0000000000000000
    raw: 0000000000000000 0000000000040004 00000000f5000000 0000000000000000
    head: 0200000000000040 ffff888100043040 dead000000000122 0000000000000000
    head: 0000000000000000 0000000000040004 00000000f5000000 0000000000000000
    head: 0200000000000003 fffffffffffffe01 00000000ffffffff 00000000ffffffff
    head: ffff888104be1f50 0000000000000000 00000000ffffffff 0000000000000000
    page dumped because: kasan: bad access detected
    
    Memory state around the buggy address:
     ffff888104be0200: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
     ffff888104be0280: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
    >ffff888104be0300: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
                          ^
     ffff888104be0380: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
     ffff888104be0400: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
    ==================================================================

Fixes: 07b87f9eea0c ("xfrm: Fix unregister netdevice hang on hardware offload.")
Signed-off-by: Cen Zhang <zzzccc427@gmail.com>
Assisted-by: LLM

---
 net/xfrm/xfrm_user.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c
index a5fbe38839c4..e9dd98c387da 100644
--- a/net/xfrm/xfrm_user.c
+++ b/net/xfrm/xfrm_user.c
@@ -1179,8 +1179,11 @@ static void copy_to_user_state(struct xfrm_state *x, struct xfrm_usersa_info *p)
 	memcpy(&p->id, &x->id, sizeof(p->id));
 	memcpy(&p->sel, &x->sel, sizeof(p->sel));
 	memcpy(&p->lft, &x->lft, sizeof(p->lft));
+	/* Pairs with synchronize_net() in netdevice unregistration. */
+	rcu_read_lock();
 	if (x->xso.dev)
 		xfrm_dev_state_update_stats(x);
+	rcu_read_unlock();
 	memcpy(&p->curlft, &x->curlft, sizeof(p->curlft));
 	put_unaligned(x->stats.replay_window, &p->stats.replay_window);
 	put_unaligned(x->stats.replay, &p->stats.replay);

^ permalink raw reply related	[flat|nested] only message in thread

only message in thread, other threads:[~2026-10-29  3:18 UTC | newest]

Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-29  3:18 [PATCH ipsec] xfrm: protect offload statistics device access with RCU Cen Zhang

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox