From: Daniel Wade <danjwade95@gmail.com>
To: "Martin K. Petersen" <mkp@kernel.org>
Cc: Maurizio Lombardi <mlombard@redhat.com>,
linux-scsi@vger.kernel.org, target-devel@vger.kernel.org,
linux-kernel@vger.kernel.org
Subject: [PATCH] scsi: target: iscsi: queue login_work under sk_callback_lock
Date: Sun, 15 Nov 2026 18:00:03 +1030 [thread overview]
Message-ID: <20261115073003.9927-1-danjwade95@gmail.com> (raw)
iscsi_target_sk_state_change() drops sk_callback_lock before queueing
conn->login_work:
write_unlock_bh(&sk->sk_callback_lock);
orig_state_change(sk);
if (!state)
schedule_delayed_work(&conn->login_work, 0);
Racing this, iscsi_target_do_login_rx() can take its err: path, which
restores the socket callbacks, calls cancel_delayed_work() and then
frees conn. The cancel does not help: the callback read conn from
sk->sk_user_data before the unlock, so clearing it changes nothing, and
cancel_delayed_work() cannot cancel a queueing that has not happened
yet. Nor can the err: path wait for it, being itself login_work.
The callback can therefore queue login_work after the cancel has run,
and conn is freed with that work still linked on a worker pool's list.
The core then unlinks it, reading the list pointers out of the freed
object and writing through them:
BUG: KASAN: slab-use-after-free in __list_del_entry_valid_or_report
Read of size 8 at addr ffff88800d94c440 by task kworker/1:2/32
Call Trace:
move_linked_works+0xa7/0x2a0
assign_work+0x168/0x3c0
worker_thread+0x3f2/0xd10
Freed by task 32:
kfree+0x179/0x530
iscsi_target_do_login_rx+0x3b7/0x7e0
Last potentially related work creation:
queue_delayed_work_on+0x80/0x90
tcp_fin+0x238/0x470
CONFIG_DEBUG_LIST catches it there; without it the unlink proceeds.
The window is a couple of microseconds against an idle target, but it
widens to milliseconds while many logins are in flight. An
unauthenticated initiator looping logins against 64 portals faulted an
unmodified 6.12.117 once in 19577 attempts, on a stock config with no
sanitizers, that time inside iscsi_target_do_login_rx() itself:
conn->tpg read back as NULL from the freed conn, and tpg_state_lock is
at offset 0x1c. An unprivileged local user reaching the portal on
loopback hits it far more often, about once per 258 attempts.
Either path oopses in a kworker. With panic_on_oops set the machine goes
down with it. No credentials are needed: the race is in login negotiation,
so any host able to reach the portal can trigger it.
iscsi_target_sk_data_ready() already queues login_work while holding
sk_callback_lock. Doing the same here makes the read of conn and the
queueing atomic against iscsi_target_restore_sock_callbacks(), which
clears sk->sk_user_data under the same lock. Either the work is queued
first and the following cancel_delayed_work() finds it, or the clear
happens first and the callback returns at the !conn check without
queueing. orig_state_change() is still called after the unlock.
With the patch applied that local reproducer makes 11212 attempts without
a fault.
Fixes: 25cdda95fda7 ("iscsi-target: Fix initial login PDU asynchronous socket close OOPs")
Cc: stable@vger.kernel.org
Signed-off-by: Daniel Wade <danjwade95@gmail.com>
---
drivers/target/iscsi/iscsi_target_nego.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/target/iscsi/iscsi_target_nego.c b/drivers/target/iscsi/iscsi_target_nego.c
index b03ed15..85531d6 100644
--- a/drivers/target/iscsi/iscsi_target_nego.c
+++ b/drivers/target/iscsi/iscsi_target_nego.c
@@ -715,12 +715,12 @@ static void iscsi_target_sk_state_change(struct sock *sk)
pr_debug("iscsi_target_sk_state_change got failed state\n");
set_bit(LOGIN_FLAGS_CLOSED, &conn->login_flags);
state = test_bit(LOGIN_FLAGS_INITIAL_PDU, &conn->login_flags);
+ if (!state)
+ schedule_delayed_work(&conn->login_work, 0);
write_unlock_bh(&sk->sk_callback_lock);
orig_state_change(sk);
- if (!state)
- schedule_delayed_work(&conn->login_work, 0);
return;
}
write_unlock_bh(&sk->sk_callback_lock);
reply other threads:[~2026-11-15 7:31 UTC|newest]
Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
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=20261115073003.9927-1-danjwade95@gmail.com \
--to=danjwade95@gmail.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-scsi@vger.kernel.org \
--cc=mkp@kernel.org \
--cc=mlombard@redhat.com \
--cc=target-devel@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®