From: sashiko-bot@kernel.org
To: "Yehyeong Lee" <yhlee@isslab.korea.ac.kr>
Cc: linux-rdma@vger.kernel.org, target-devel@vger.kernel.org
Subject: Re: [PATCH] IB/isert: set ISER_CONN_DOWN only after the connection has been released
Date: Mon, 26 Oct 2026 00:20:43 +0000 [thread overview]
Message-ID: <sashiko-outbox-184560@kernel.org> (raw)
In-Reply-To: <20261026000733.4178856-1-yhlee@isslab.korea.ac.kr>
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [Critical] IB/isert: UAF on rem_wait in isert_connect_release() after ISER_CONN_DOWN
- [High] IB/isert: deadlock on handler_mutex in isert_connect_release() on device removal
--
commit dc719d99e88528503ed27ec0d20e073beee4b8f9
Author: Yehyeong Lee <yhlee@isslab.korea.ac.kr>
IB/isert: set ISER_CONN_DOWN only after the connection has been released
This commit moves the store setting isert_conn->state to ISER_CONN_DOWN from
isert_release_work() into isert_connect_release() right before waking
isert_conn->rem_wait. This is intended to prevent the
RDMA_CM_EVENT_DEVICE_REMOVAL handler in isert_cma_handler() from freeing
isert_conn while isert_connect_release() is still tearing down connection
resources.
> diff --git a/drivers/infiniband/ulp/isert/ib_isert.c b/drivers/infiniband/ulp/isert/ib_isert.c
> index efa8d7b7844c9..cd0ca3cf131cb 100644
> --- a/drivers/infiniband/ulp/isert/ib_isert.c
> +++ b/drivers/infiniband/ulp/isert/ib_isert.c
> @@ -506,10 +506,18 @@ isert_connect_release(struct isert_conn *isert_conn)
>
> isert_device_put(device);
>
> - if (isert_conn->dev_removed)
> + if (isert_conn->dev_removed) {
> + /*
> + * Publish ISER_CONN_DOWN only now. The
> + * RDMA_CM_EVENT_DEVICE_REMOVAL handler waits for it and then
> + * frees isert_conn, so it must not become visible before the
> + * teardown above has finished using the connection.
> + */
> + isert_conn->state = ISER_CONN_DOWN;
> wake_up_interruptible(&isert_conn->rem_wait);
[Severity: Critical]
Can publishing isert_conn->state = ISER_CONN_DOWN before calling
wake_up_interruptible(&isert_conn->rem_wait) cause a use-after-free on
isert_conn->rem_wait when racing with kfree(isert_conn) in
isert_cma_handler()?
In drivers/infiniband/ulp/isert/ib_isert.c, isert_cma_handler() handles
RDMA_CM_EVENT_DEVICE_REMOVAL with:
case RDMA_CM_EVENT_DEVICE_REMOVAL:
isert_conn = cma_id->qp->qp_context;
isert_conn->dev_removed = true;
isert_disconnected_handler(cma_id, event->event);
wait_event_interruptible(isert_conn->rem_wait,
isert_conn->state == ISER_CONN_DOWN);
kfree(isert_conn);
Because rem_wait is embedded inside struct isert_conn and
wait_event_interruptible() checks isert_conn->state == ISER_CONN_DOWN before
acquiring rem_wait.lock (and again after prepare_to_wait_event() before
schedule()), as soon as the store to isert_conn->state becomes visible on
another CPU, wait_event_interruptible() can return immediately and call
kfree(isert_conn) before wake_up_interruptible(&isert_conn->rem_wait) even
begins. In that fast-path case, no barrier in wake_up_interruptible() has
executed to order prior accesses in isert_connect_release() before
kfree(isert_conn), and wake_up_interruptible() -> __wake_up_common_lock() ->
spin_lock_irqsave(&wq_head->lock, flags) will then dereference and write to
the freed isert_conn->rem_wait.
Even when the waiter is asleep in schedule(), __wake_up_common_lock() invokes
autoremove_wake_function(), which wakes the task and removes wq_entry from
rem_wait.head via list_del_init_careful(&wq_entry->entry) before releasing
rem_wait.lock. The woken waiter can observe isert_conn->state ==
ISER_CONN_DOWN, see list_empty_careful(&wq_entry->entry) in finish_wait()
without taking rem_wait.lock, and call kfree(isert_conn) while
__wake_up_common_lock() in isert_connect_release() is still traversing
rem_wait.head and unlocking isert_conn->rem_wait.lock.
Would replacing rem_wait with a struct completion (using complete() and
wait_for_completion_interruptible(), which serialize completion state and
waiter exit under the completion's wait.lock) avoid this race?
> - else
> + } else {
> kfree(isert_conn);
> + }
> }
>
> static void
> @@ -2537,10 +2545,6 @@ static void isert_release_work(struct work_struct *work)
>
> isert_info("Starting release conn %p\n", isert_conn);
>
> - mutex_lock(&isert_conn->mutex);
> - isert_conn->state = ISER_CONN_DOWN;
> - mutex_unlock(&isert_conn->mutex);
[Severity: High]
Does moving the ISER_CONN_DOWN transition from isert_release_work() to the end
of isert_connect_release() introduce a deadlock on id_priv->handler_mutex when
a normal connection teardown races with RDMA device removal?
In drivers/infiniband/ulp/isert/ib_isert.c, isert_connect_release() runs after
isert_release_work() drops the last reference and checks dev_removed before
destroying the CM ID:
static void
isert_connect_release(struct isert_conn *isert_conn)
{
...
if (isert_conn->cm_id &&
!isert_conn->dev_removed)
rdma_destroy_id(isert_conn->cm_id);
If a connection begins normal teardown prior to device removal (for example,
via RDMA_CM_EVENT_DISCONNECTED or iscsit_close_connection() ->
isert_wait_conn()), isert_conn->state is set to ISER_CONN_TERMINATING with
isert_conn->dev_removed == false, and isert_release_work() invokes
isert_connect_release().
If isert_connect_release() observes !isert_conn->dev_removed and enters
rdma_destroy_id(isert_conn->cm_id) just as cma_remove_one() ->
cma_process_remove() -> cma_send_device_removal_put() acquires
id_priv->handler_mutex first:
CPU0 (isert_release_wq) CPU1 (device removal)
isert_release_work()
isert_put_conn()
isert_connect_release()
sees !isert_conn->dev_removed
rdma_destroy_id(cm_id)
cma_send_device_removal_put()
mutex_lock(&id_priv->handler_mutex)
cma_ndev_work / cma_cm_event_handler
isert_cma_handler()
isert_conn->dev_removed = true
isert_disconnected_handler()
(sees ISER_CONN_TERMINATING)
wait_event_interruptible(
isert_conn->rem_wait,
state == ISER_CONN_DOWN)
mutex_lock(&id_priv->handler_mutex)
Because ISER_CONN_DOWN is now set only after rdma_destroy_id() returns in
isert_connect_release(), CPU0 blocks waiting for id_priv->handler_mutex inside
rdma_destroy_id() while CPU1 holds id_priv->handler_mutex waiting for
isert_conn->state == ISER_CONN_DOWN. Furthermore, if the interruptible wait on
CPU1 is interrupted by a signal, isert_cma_handler() frees isert_conn and
returns 1 to destroy cm_id while rdma_destroy_id() on CPU0 proceeds to destroy
cm_id a second time and then accesses the freed isert_conn.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261026000733.4178856-1-yhlee@isslab.korea.ac.kr?part=1
next prev parent reply other threads:[~2026-10-26 0:20 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-26 0:07 [PATCH] IB/isert: set ISER_CONN_DOWN only after the connection has been released Yehyeong Lee
2026-10-26 0:20 ` sashiko-bot [this message]
2026-10-26 4:43 ` Yehyeong Lee
2026-10-26 4:19 ` [PATCH v2] IB/isert: tear connections down from an ib_client on device removal Yehyeong Lee
2026-10-26 9:09 ` sashiko-bot
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=sashiko-outbox-184560@kernel.org \
--to=sashiko-bot@kernel.org \
--cc=linux-rdma@vger.kernel.org \
--cc=sashiko-reviews@lists.linux.dev \
--cc=target-devel@vger.kernel.org \
--cc=yhlee@isslab.korea.ac.kr \
/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