mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Cen Zhang <zzzccc427@gmail.com>
To: steffen.klassert@secunet.com, herbert@gondor.apana.org.au,
	davem@davemloft.net, edumazet@google.com, kuba@kernel.org,
	pabeni@redhat.com
Cc: horms@kernel.org, netdev@vger.kernel.org,
	linux-kernel@vger.kernel.org, baijiaju1990@gmail.com,
	jjzuming@gmail.com, zzzccc427@gmail.com
Subject: [PATCH ipsec 1/2] xfrm: keep old state references until migration deletion completes
Date: Sat, 31 Oct 2026 12:14:54 +0800	[thread overview]
Message-ID: <pm-xfrm-core-objects-candidate-0027-v3-cb1e033bff1976f510c9-1@gmail.com> (raw)
In-Reply-To: <pm-xfrm-core-objects-candidate-0027-v3-cb1e033bff1976f510c9-0@gmail.com>

xfrm_migrate() must retain the references returned by
xfrm_migrate_state_find() until it finishes using the old states. The
successful migration path instead calls xfrm_states_put() before
xfrm_states_delete(), leaving the latter to use unreferenced pointers
from x_cur[].

With CONFIG_XFRM_MIGRATE enabled, a privileged XFRM_MSG_MIGRATE or
SADB_X_MIGRATE request can reach this path for an SA with a finite hard
lifetime and no other users. If migration is preempted after the put,
the old SA can expire and be reclaimed before deletion resumes:

  Migration task                 Hard-expiry timer / GC worker
  --------------                 -----------------------------
  xfrm_migrate_state_find()
    hold old SA in x_cur[]
  migrate state and policy
  xfrm_states_put(x_cur, ...)
    drop lookup reference
                                 xfrm_timer_handler()
                                   __xfrm_state_delete(old SA)
                                     drop SAD reference
                                 xfrm_state_gc_task()
                                   synchronize_rcu()
                                   free old SA
  xfrm_states_delete(x_cur, ...)
    xfrm_state_delete(old SA)
      spin_lock_bh(&x->lock) /* use after free */

The configuration mutex does not serialize migration with the timer or
GC worker, and migration holds no RCU read lock across this interval.
xfrm_state_delete() accesses the freed lock before it can check whether
the state is already dead. Expiry before the migration put can open the
same window, with that put dropping the last reference.

Delete the old states before putting their lookup references. Each state
then remains allocated through the lock access and the dead-state check,
including when expiry has already removed it from the SAD.

KASAN report as below:

    ==================================================================
    BUG: KASAN: slab-use-after-free in _raw_spin_lock_bh+0x38/0x50
    Read of size 1 at addr ffff88810967af48 by task python3/443

    Call Trace:
     <TASK>
     dump_stack_lvl+0x93/0xd0
     print_report+0xce/0x630
     kasan_report+0xe0/0x110
     __kasan_check_byte+0x36/0x50
     lock_acquire+0x113/0x2f0
     _raw_spin_lock_bh+0x38/0x50
     xfrm_state_delete+0x26/0x60
     xfrm_migrate+0xd26/0x1950
     xfrm_do_migrate+0x797/0xad0
     xfrm_user_rcv_msg+0x3b3/0xc20
     netlink_rcv_skb+0x133/0x390
     xfrm_netlink_rcv+0x76/0x90
     netlink_unicast+0x504/0x840
     netlink_sendmsg+0x7f7/0xcf0
     __sys_sendto+0x425/0x470
     __x64_sys_sendto+0xe5/0x1c0
     do_syscall_64+0x115/0x6a0
     entry_SYSCALL_64_after_hwframe+0x77/0x7f
     </TASK>

    Allocated by task 424:
     kasan_save_stack+0x33/0x60
     kasan_save_track+0x14/0x30
     __kasan_slab_alloc+0x89/0x90
     kmem_cache_alloc_noprof+0x20b/0x5f0
     xfrm_state_alloc+0x28/0x5d0
     xfrm_add_sa+0xb81/0x5660
     xfrm_user_rcv_msg+0x3b3/0xc20
     netlink_rcv_skb+0x133/0x390
     xfrm_netlink_rcv+0x76/0x90
     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 66:
     kasan_save_stack+0x33/0x60
     kasan_save_track+0x14/0x30
     kasan_save_free_info+0x3b/0x60
     __kasan_slab_free+0x5f/0x80
     kmem_cache_free+0x242/0x580
     xfrm_state_gc_task+0x534/0x780
     process_one_work+0x908/0x19c0
     worker_thread+0x65c/0xe40
     kthread+0x34f/0x460
     ret_from_fork+0x659/0x940
     ret_from_fork_asm+0x1a/0x30

    The buggy address belongs to the object at ffff88810967aec0
     which belongs to the cache xfrm_state of size 936
    The buggy address is located 136 bytes inside of
     freed 936-byte region [ffff88810967aec0, ffff88810967b268)
    ==================================================================

Fixes: 80c9abaabf42 ("[XFRM]: Extension for dynamic update of endpoint address(es)")
Signed-off-by: Cen Zhang <zzzccc427@gmail.com>
---
Assisted-by: LLM

 net/xfrm/xfrm_policy.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
index 0f6fcea28bcd..55f6bacc4e51 100644
--- a/net/xfrm/xfrm_policy.c
+++ b/net/xfrm/xfrm_policy.c
@@ -4726,8 +4726,8 @@ int xfrm_migrate(const struct xfrm_selector *sel, u8 dir, u8 type,
 
 	/* Stage 4 - delete old state(s) */
 	if (nx_cur) {
-		xfrm_states_put(x_cur, nx_cur);
 		xfrm_states_delete(x_cur, nx_cur);
+		xfrm_states_put(x_cur, nx_cur);
 	}
 
 	/* Stage 5 - announce */

  reply	other threads:[~2026-10-31  4:15 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-31  4:14 [PATCH ipsec 0/2] xfrm: fix state lifetimes in xfrm_migrate() Cen Zhang
2026-10-31  4:14 ` Cen Zhang [this message]
2026-10-31  4:14 ` [PATCH ipsec 2/2] xfrm: hold migrated states through rollback Cen Zhang
2026-10-31  4:18 ` [PATCH ipsec 0/2] xfrm: fix state lifetimes in xfrm_migrate() netdev-bot+sinfo

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=pm-xfrm-core-objects-candidate-0027-v3-cb1e033bff1976f510c9-1@gmail.com \
    --to=zzzccc427@gmail.com \
    --cc=baijiaju1990@gmail.com \
    --cc=davem@davemloft.net \
    --cc=edumazet@google.com \
    --cc=herbert@gondor.apana.org.au \
    --cc=horms@kernel.org \
    --cc=jjzuming@gmail.com \
    --cc=kuba@kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=netdev@vger.kernel.org \
    --cc=pabeni@redhat.com \
    --cc=steffen.klassert@secunet.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®