[PATCH v3 1/2] IB/isert: do not publish connections being released on a second list
From: Yehyeong Lee
Date: Mon Nov 02 2026 - 01:17:13 EST
isert_free_np() moves the connections left on isert_np->pending and
isert_np->accepted onto a stack-local list, drops isert_np->mutex and
releases them from there. isert_conn->node is then linked into that
local list instead of being empty, which is the test
isert_handle_unbound_conn() uses to decide whether a connection still
needs cleaning up. It runs from the RDMA CM handler, which is not
serialised against isert_free_np(), so it unlinks the connection from a
list it does not own and queues a second release for it.
Take the connections off isert_np one at a time, so that
isert_conn->node is empty once isert_np->mutex is dropped. The release
keeps running with no mutex held, which commit 691b0480933f ("IB/isert:
Fix dead lock in ib_isert") needs: releasing a connection destroys its
cm_id, and rdma_destroy_id() waits for the handler_mutex that the CM
handler holds while it waits for isert_np->mutex.
Reproduced with a test-only delay added inside isert_free_np()'s release
loop: 36 reports in each of three unpatched runs, none in three patched
runs.
BUG: KASAN: slab-use-after-free in isert_free_np+0x6a4/0xab0
Read of size 8 at addr ffff888109249040 by task rmdir/193
CPU: 1 UID: 0 PID: 193 Comm: rmdir Not tainted 7.3.0-BASET-13248-g103b309e2033 #15 PREEMPT(full)
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+0x53/0x70
print_report+0xd0/0x630
? __pfx__raw_spin_lock_irqsave+0x10/0x10
? isert_free_np+0x6a4/0xab0
kasan_report+0xce/0x100
? isert_free_np+0x6a4/0xab0
isert_free_np+0x6a4/0xab0
? __pfx_isert_free_np+0x10/0x10
iscsit_del_np+0x163/0x340
iscsit_tpg_del_network_portal+0x3c3/0x530
? mutex_unlock+0x7b/0xd0
lio_target_call_delnpfromtpg+0x40/0x60
config_item_cleanup+0x115/0x190
configfs_rmdir+0x7c7/0x9f0
? __pfx_configfs_rmdir+0x10/0x10
vfs_rmdir+0x291/0x770
? lookup_one_qstr_excl+0x1a/0x1d0
filename_rmdir+0x35d/0x4f0
? __pfx_filename_rmdir+0x10/0x10
? kasan_save_track+0x14/0x30
? __kasan_slab_alloc+0x6e/0x70
? strncpy_from_user+0x2b/0x1c0
__x64_sys_rmdir+0x41/0x60
do_syscall_64+0xdd/0x4a0
entry_SYSCALL_64_after_hwframe+0x77/0x7f
</TASK>
Allocated by task 10:
kasan_save_stack+0x33/0x60
kasan_save_track+0x14/0x30
__kasan_kmalloc+0x8f/0xa0
__kmalloc_cache_noprof+0x148/0x360
isert_cma_handler+0x1e3/0x2840
cma_cm_event_handler+0x3e/0x240
cma_ib_req_handler+0x17d9/0x4480
cm_process_work+0x41/0x330
cm_work_handler+0x5727/0xc160
process_one_work+0x697/0x1060
worker_thread+0x45b/0xd10
kthread+0x2c8/0x3b0
ret_from_fork+0x36e/0x5a0
ret_from_fork_asm+0x1a/0x30
Freed by task 43:
kasan_save_stack+0x33/0x60
kasan_save_track+0x14/0x30
kasan_save_free_info+0x3b/0x60
__kasan_slab_free+0x43/0x70
kfree+0x121/0x390
process_one_work+0x697/0x1060
worker_thread+0x45b/0xd10
kthread+0x2c8/0x3b0
ret_from_fork+0x36e/0x5a0
ret_from_fork_asm+0x1a/0x30
Last potentially related work creation:
kasan_save_stack+0x33/0x60
kasan_record_aux_stack+0x8c/0xa0
__queue_work+0x7a1/0x15e0
queue_work_on+0x5d/0x70
isert_disconnected_handler.isra.0+0x20b/0x380
isert_cma_handler+0xd71/0x2840
cma_cm_event_handler+0x3e/0x240
cma_ib_handler+0x190/0x750
cm_process_work+0x41/0x330
cm_work_handler+0x582b/0xc160
process_one_work+0x697/0x1060
worker_thread+0x45b/0xd10
kthread+0x2c8/0x3b0
ret_from_fork+0x36e/0x5a0
ret_from_fork_asm+0x1a/0x30
The buggy address belongs to the object at ffff888109248000
which belongs to the cache kmalloc-8k of size 8192
The buggy address is located 4160 bytes inside of
freed 8192-byte region [ffff888109248000, ffff88810924a000)
Fixes: 691b0480933f ("IB/isert: Fix dead lock in ib_isert")
Cc: stable@xxxxxxxxxxxxxxx
Signed-off-by: Yehyeong Lee <yhlee@xxxxxxxxxxxxxxxxxx>
---
drivers/infiniband/ulp/isert/ib_isert.c | 54 ++++++++++++++-----------
1 file changed, 31 insertions(+), 23 deletions(-)
diff --git a/drivers/infiniband/ulp/isert/ib_isert.c b/drivers/infiniband/ulp/isert/ib_isert.c
index efa8d7b7844c97..5371bba71ba3cb 100644
--- a/drivers/infiniband/ulp/isert/ib_isert.c
+++ b/drivers/infiniband/ulp/isert/ib_isert.c
@@ -2479,12 +2479,29 @@ isert_accept_np(struct iscsi_np *np, struct iscsit_conn *conn)
return 0;
}
+static struct isert_conn *
+isert_np_take_conn(struct isert_np *isert_np)
+{
+ struct isert_conn *isert_conn;
+
+ lockdep_assert_held(&isert_np->mutex);
+
+ isert_conn = list_first_entry_or_null(&isert_np->pending,
+ struct isert_conn, node);
+ if (!isert_conn)
+ isert_conn = list_first_entry_or_null(&isert_np->accepted,
+ struct isert_conn, node);
+ if (isert_conn)
+ list_del_init(&isert_conn->node);
+
+ return isert_conn;
+}
+
static void
isert_free_np(struct iscsi_np *np)
{
struct isert_np *isert_np = np->np_context;
- struct isert_conn *isert_conn, *n;
- LIST_HEAD(drop_conn_list);
+ struct isert_conn *isert_conn;
if (isert_np->cm_id)
rdma_destroy_id(isert_np->cm_id);
@@ -2497,31 +2514,22 @@ isert_free_np(struct iscsi_np *np)
* up in accepted and pending lists.
*/
mutex_lock(&isert_np->mutex);
- if (!list_empty(&isert_np->pending)) {
+ if (!list_empty(&isert_np->pending))
isert_info("Still have isert pending connections\n");
- list_for_each_entry_safe(isert_conn, n,
- &isert_np->pending,
- node) {
- isert_info("cleaning isert_conn %p state (%d)\n",
- isert_conn, isert_conn->state);
- list_move_tail(&isert_conn->node, &drop_conn_list);
- }
- }
-
- if (!list_empty(&isert_np->accepted)) {
+ if (!list_empty(&isert_np->accepted))
isert_info("Still have isert accepted connections\n");
- list_for_each_entry_safe(isert_conn, n,
- &isert_np->accepted,
- node) {
- isert_info("cleaning isert_conn %p state (%d)\n",
- isert_conn, isert_conn->state);
- list_move_tail(&isert_conn->node, &drop_conn_list);
- }
- }
mutex_unlock(&isert_np->mutex);
- list_for_each_entry_safe(isert_conn, n, &drop_conn_list, node) {
- list_del_init(&isert_conn->node);
+ for (;;) {
+ mutex_lock(&isert_np->mutex);
+ isert_conn = isert_np_take_conn(isert_np);
+ mutex_unlock(&isert_np->mutex);
+
+ if (!isert_conn)
+ break;
+
+ isert_info("cleaning isert_conn %p state (%d)\n",
+ isert_conn, isert_conn->state);
isert_connect_release(isert_conn);
}
--
2.43.0