From: Bernard Metzler <bernard.metzler@linux.dev>
To: Jaeyeong Lee <lee@jaeyeong.cc>
Cc: Jason Gunthorpe <jgg@ziepe.ca>, Leon Romanovsky <leon@kernel.org>,
linux-rdma@vger.kernel.org, linux-kernel@vger.kernel.org
Subject: Re: [PATCH v3] RDMA/siw: Fix early peer close handling on listeners
Date: Fri, 6 Nov 2026 12:40:12 +0100 [thread overview]
Message-ID: <2a6c5985-6767-4eb4-88a6-3d53196ec5bd@linux.dev> (raw)
In-Reply-To: <20261105022253.368316-1-lee@jaeyeong.cc>
On 05.11.2026 03:22, Jaeyeong Lee wrote:
> A TCP child socket inherits the listener callbacks and sk_user_data before
> kernel_accept() associates it with a new connection endpoint. If the peer
> closes during this window, siw_cm_llp_state_change() queues a PEER_CLOSE
> work item against the listening endpoint.
>
> The worker releases that endpoint without removing it from the listener
> list. A later listener teardown then walks the dangling entry, causing a
> use-after-free in siw_destroy_listen(). KASAN reports:
>
> ==================================================================
> BUG: KASAN: slab-use-after-free in __list_del_entry_valid_or_report+0x32/0x1a0
> Read of size 8 at addr ffff888008f502c8 by task rping/59
>
> CPU: 0 UID: 0 PID: 59 Comm: rping Tainted: G B 7.4.0-rc1-g6628e7d4c6b2 #1 PREEMPT(lazy)
> Tainted: [B]=BAD_PAGE
> 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+0x54/0x70
> print_address_description+0x73/0x1f0
> ? __list_del_entry_valid_or_report+0x32/0x1a0
> print_report+0x58/0x70
> kasan_report+0x117/0x150
> ? add_taint+0x43/0x90
> ? __list_del_entry_valid_or_report+0x32/0x1a0
> __list_del_entry_valid_or_report+0x32/0x1a0
> siw_destroy_listen+0xe1/0x630
> destroy_cm_id+0x25c/0x480
> ? srso_return_thunk+0x5/0x5f
> ? srso_return_thunk+0x5/0x5f
> ? lock_acquire+0xf7/0x220
> ? _destroy_id+0x2d1/0xe30
> iw_destroy_cm_id+0xf/0x80
> _destroy_id+0x6cc/0xe30
> _cma_cancel_listens+0x2ee/0x360
> _destroy_id+0x2ad/0xe30
> ucma_destroy_private_ctx+0xb7/0x9d0
> ? srso_return_thunk+0x5/0x5f
> ? do_raw_spin_unlock+0x4d/0x230
> ucma_close+0xd5/0x130
> __fput+0x31a/0x720
> fput_close_sync+0x91/0x110
> filp_close_sync+0x18/0x30
> put_files_struct+0x25a/0x280
> do_exit+0x70e/0x1d00
> ? lock_acquire+0xf7/0x220
> ? get_signal+0x21c/0xf60
> do_group_exit+0x19e/0x250
> get_signal+0xf20/0xf60
> ? futex_wait+0x99/0x230
> arch_do_signal_or_restart+0x46/0x420
> exit_to_user_mode_loop+0xbd/0x510
> do_syscall_64+0x2ed/0x3b0
> ? entry_SYSCALL_64_after_hwframe+0x76/0x7e
> ? srso_return_thunk+0x5/0x5f
> ? trace_hardirqs_off+0x65/0x90
> entry_SYSCALL_64_after_hwframe+0x76/0x7e
> RIP: 0033:0x7f92984c6e51
> Code: Unable to access opcode bytes at 0x7f92984c6e27.
> RSP: 002b:00007ffeae782d10 EFLAGS: 00000246 ORIG_RAX: 00000000000000ca
> RAX: fffffffffffffe00 RBX: 000055fb4e9819b8 RCX: 00007f92984c6e51
> RDX: 0000000000000000 RSI: 0000000000000189 RDI: 000055fb4e9819b8
> RBP: 00007ffeae782d50 R08: 0000000000000000 R09: 00000000ffffffff
> R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000000
> R13: 0000000000000000 R14: 000055fb4e9819b8 R15: 000055fb4e97da25
> </TASK>
>
> Allocated by task 59:
> kasan_save_track+0x3e/0x80
> __kasan_kmalloc+0x72/0x90
> __kmalloc_cache_noprof+0x245/0x3c0
> siw_cep_alloc+0x4f/0x390
> siw_create_listen+0x39e/0xd60
> iw_cm_listen+0xfc/0x1d0
> rdma_listen+0x749/0xa90
> cma_listen_on_dev+0x404/0x760
> rdma_listen+0x3dc/0xa90
> ucma_listen+0xe2/0x180
> ucma_write+0x1bd/0x1e0
> vfs_write+0x1a9/0x8e0
> ksys_write+0xba/0x180
> do_syscall_64+0xee/0x3b0
> entry_SYSCALL_64_after_hwframe+0x76/0x7e
>
> Freed by task 30:
> kasan_save_track+0x3e/0x80
> kasan_save_free_info+0x40/0x50
> __kasan_slab_free+0x3a/0x60
> kfree+0x155/0x470
> siw_cm_work_handler+0x7af/0x2d40
> process_scheduled_works+0x970/0x12d0
> worker_thread+0x894/0xd20
> kthread+0x2db/0x3b0
> ret_from_fork+0x266/0x570
> ret_from_fork_asm+0x1a/0x30
>
> The buggy address belongs to the object at ffff888008f50200
> which belongs to the cache kmalloc-512 of size 512
> The buggy address is located 200 bytes inside of
> freed 512-byte region [ffff888008f50200, ffff888008f50400)
>
> The buggy address belongs to the physical page:
> page: refcount:0 mapcount:0 mapping:0000000000000000
> index:0xffff888008f51400 pfn:0x8f50
> head: order:2 mapcount:0 entire_mapcount:0 nr_pages_mapped:0 pincount:0
> flags: 0x4000000000000240(workingset|head|zone=1)
> page_type: f5(slab)
> raw: 4000000000000240 ffff888005842040 ffff888005840d08 ffff888005840d08
> raw: ffff888008f51400 00000000000a0003 00000000f5000000 0000000000000000
> head: 4000000000000240 ffff888005842040 ffff888005840d08 ffff888005840d08
> head: ffff888008f51400 00000000000a0003 00000000f5000000 0000000000000000
> head: 4000000000000002 ffffea000023d401 00000000ffffffff 00000000ffffffff
> head: 0000000000000000 0000000000000000 00000000ffffffff 0000000000000000
> page dumped because: kasan: bad access detected
>
> Memory state around the buggy address:
> ffff888008f50180: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
> ffff888008f50200: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
> >ffff888008f50280: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
> ^
> ffff888008f50300: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
> ffff888008f50380: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
> ==================================================================
>
> There is a second race while creating a listener. listen() starts
> accepting connections before the endpoint is linked to the CM ID and
> changed from IDLE to LISTENING. ACCEPT work queued in this interval can
> run immediately, see the IDLE state, and return without accepting the
> first child.
>
> Keep the listener endpoint in use from allocation until its CM ID, listener
> list entry, and LISTENING state have all been published. This makes early
> ACCEPT work wait for listener setup to complete.
>
> During accept, serialize the endpoint handoff with socket state changes and
> reject a child that has already reached TCP_CLOSE or TCP_CLOSE_WAIT. Ignore
> close notifications inherited from the listener before that handoff. Live
> accepted sockets continue through the normal close path.
>
> The issue was found by static analysis.
>
> The unpatched kernel reproduced the KASAN report above in an x86_64 QEMU
> guest. With a temporary 500 ms delay after listen(), the previous version
> lost the first child and timed out waiting for an MPA response; this
> version accepted the same child and returned an MPA response.
> RST-before-accept and MPA-request-followed-by-FIN tests also completed
> without KASAN or lockdep reports. The final SIW object was built with
> LLVM 22.1.8 and W=1.
>
> Fixes: 6c52fdc244b5 ("rdma/siw: connection management")
> Suggested-by: Stefan Metzmacher <metze@samba.org>
> Link: https://lore.kernel.org/r/33abff2233b36a51e468d691cb4327d0294d2734.1620343860.git.metze@samba.org
> Cc: stable@vger.kernel.org
> Signed-off-by: Jaeyeong Lee <lee@jaeyeong.cc>
> ---
> Changes in v3:
> - Serialize listener setup so early ACCEPT work cannot be consumed in IDLE.
> - Include the complete KASAN report requested by Leon.
>
> Changes in v2:
> - Cover the IDLE interval between listen() and the LISTENING transition.
> - Serialize accepted-socket handoff and reject an already closed child.
>
> drivers/infiniband/sw/siw/siw_cm.c | 23 ++++++++++++++++++++---
> 1 file changed, 20 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/infiniband/sw/siw/siw_cm.c b/drivers/infiniband/sw/siw/siw_cm.c
> index ed49818793dde..90adb9543d9d0 100644
> --- a/drivers/infiniband/sw/siw/siw_cm.c
> +++ b/drivers/infiniband/sw/siw/siw_cm.c
> @@ -973,6 +973,7 @@ static void siw_accept_newconn(struct siw_cep *cep)
> struct socket *s = cep->sock;
> struct socket *new_s = NULL;
> struct siw_cep *new_cep = NULL;
> + bool peer_closed;
> int rv = 0; /* debug only. should disappear */
>
> if (cep->state != SIW_EPSTATE_LISTENING)
> @@ -1009,11 +1010,23 @@ static void siw_accept_newconn(struct siw_cep *cep)
> }
> new_cep->sock = new_s;
> siw_cep_get(new_cep);
> - new_s->sk->sk_user_data = new_cep;
>
> if (siw_tcp_nagle == false)
> tcp_sock_set_nodelay(new_s->sk);
> +
> + lock_sock(new_s->sk);
> + write_lock_bh(&new_s->sk->sk_callback_lock);
> new_cep->state = SIW_EPSTATE_AWAIT_MPAREQ;
> + new_s->sk->sk_user_data = new_cep;
> + peer_closed = new_s->sk->sk_state == TCP_CLOSE ||
> + new_s->sk->sk_state == TCP_CLOSE_WAIT;
> + write_unlock_bh(&new_s->sk->sk_callback_lock);
> + release_sock(new_s->sk);
> +
> + if (peer_closed) {
> + rv = -ECONNRESET;
> + goto error;
> + }
>
> rv = siw_cm_queue_work(new_cep, SIW_CM_WORK_MPATIMEOUT);
> if (rv)
> @@ -1361,6 +1374,10 @@ static void siw_cm_llp_state_change(struct sock *sk)
>
> case TCP_CLOSE:
> case TCP_CLOSE_WAIT:
> + if (cep->state == SIW_EPSTATE_LISTENING ||
> + (cep->state == SIW_EPSTATE_IDLE &&
> + !READ_ONCE(sk->sk_socket)))
> + break;
> if (cep->qp)
> cep->qp->tx_ctx.tx_suspend = 1;
> siw_cm_queue_work(cep, SIW_CM_WORK_PEER_CLOSE);
> @@ -1880,6 +1897,7 @@ int siw_create_listen(struct iw_cm_id *id, int backlog)
> rv = -ENOMEM;
> goto error;
> }
> + siw_cep_set_inuse(cep);
> siw_cep_socket_assoc(cep, s);
>
> rv = siw_cm_alloc_work(cep, backlog);
> @@ -1932,14 +1950,13 @@ int siw_create_listen(struct iw_cm_id *id, int backlog)
>
> siw_dbg(id->device, "Listen at laddr %pISp\n", &id->local_addr);
>
> + siw_cep_set_free(cep);
> return 0;
>
> error:
> siw_dbg(id->device, "failed: %d\n", rv);
>
> if (cep) {
> - siw_cep_set_inuse(cep);
> -
> siw_free_cm_id(cep);
> siw_socket_disassoc(s);
> cep->state = SIW_EPSTATE_CLOSED;
Thank you Jaeyeong. While it seems sound, I have to look
closer. I'll reply soon.
Thanks,
Bernard.
prev parent reply other threads:[~2026-11-06 11:40 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-05 2:22 Jaeyeong Lee
2026-11-06 11:40 ` Bernard Metzler [this message]
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=2a6c5985-6767-4eb4-88a6-3d53196ec5bd@linux.dev \
--to=bernard.metzler@linux.dev \
--cc=jgg@ziepe.ca \
--cc=lee@jaeyeong.cc \
--cc=leon@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-rdma@vger.kernel.org \
/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®