From: Yuanhe Shu <xiangzao@linux.alibaba.com>
To: "Martin K . Petersen" <mkp@kernel.org>
Cc: linux-scsi@vger.kernel.org, target-devel@vger.kernel.org,
linux-kernel@vger.kernel.org, stable@vger.kernel.org,
John Garry <john.garry@linux.dev>,
David Disseldorp <ddiss@suse.de>,
Bryam Vargas <hexlabsecurity@proton.me>,
xiangzao@linux.alibaba.com
Subject: [PATCH] scsi: target: Verify the iSCSI ISID is NUL-terminated
Date: Mon, 26 Oct 2026 12:46:32 +0800 [thread overview]
Message-ID: <20261026044632.1738901-1-xiangzao@linux.alibaba.com> (raw)
iscsi_parse_pr_out_transport_id() returns the ISID of a FORMAT CODE 01b
TransportID as a pointer into the PERSISTENT RESERVE OUT parameter list.
The lower-case conversion loop only scans the ISID and never terminates
it, and while spc4r37 Table 508 requires the field to be null-terminated,
a non-conforming initiator can omit the NUL. When the ISID ends at the
end of the received buffer, the pointer is not a C string.
The registration code still consumes it as one: strcmp(isid,
pr_reg->pr_reg_isid) in __core_scsi3_locate_pr_reg(), and snprintf("%s")
and strcmp() in __core_scsi3_do_alloc_registration() and in the REGISTER
AND MOVE path.
When the parameter list spans more than one page, transport_kmap_data_sg()
maps it with vmap(), and the over-read walks off the end of the mapping
into the vmalloc guard page and oopses. Reproduced with a PR OUT
REGISTER + SPEC_I_PT parameter list of exactly 8192 bytes whose final
TransportID carries a 12-byte ISID without a terminating NUL:
BUG: unable to handle page fault for address: ffffc9000138c000
RIP: 0010:strcmp+0xc/0x30
Call Trace:
__core_scsi3_locate_pr_reg+0xd3/0x120 [target_core_mod]
core_scsi3_decode_spec_i_port+0x8fc/0x13a0 [target_core_mod]
core_scsi3_emulate_pro_register+0x73c/0x900 [target_core_mod]
...
iscsi_target_rx_thread+0xef/0x1d0 [iscsi_target_mod]
With a single-page parameter list the buffer is a kmap() direct mapping,
so the over-read continues into the physically adjacent page instead of
faulting. snprintf("%s") then copies whatever follows the ISID in
memory into pr_reg_isid, and PR IN READ FULL STATUS reports the
registration back to any initiator, turning the over-read into an
info leak of kernel heap contents. Reproduced with a 4096-byte
parameter list whose last TransportID ends at the end of the buffer
with a 4-byte ISID and no NUL, interleaved with I/O to populate
adjacent pages: the READ FULL STATUS response returned the ISID as
"0xleak" followed by raw bytes that were not part of the parameter
list. The snprintf() into pr_reg_isid[PR_REG_ISID_LEN] caps the echoed
ISID at 15 characters, so at most 11 bytes past the buffer are leaked
per command, but the PR OUT command is not rate limited.
Any initiator that can send PR OUT to an iSCSI-exported LUN can trigger
either variant, including a guest via vhost-scsi.
Require the TransportID to contain the terminating NUL before the ISID
pointer is returned, so neither reproducer reaches the registration
consumers. REGISTER AND MOVE fails with TCM_INVALID_PARAMETER_LIST;
the SPEC_I_PT scan skips the entry.
Fixes: d04a179085c2 ("scsi: target: Bound PR-OUT TransportID parsing to the received buffer")
Reported-by: kitta <kitta@linux.alibaba.com>
Cc: stable@vger.kernel.org
Cc: Bryam Vargas <hexlabsecurity@proton.me>
Cc: John Garry <john.garry@linux.dev>
Assisted-by: LLM
Signed-off-by: Yuanhe Shu <xiangzao@linux.alibaba.com>
---
drivers/target/target_core_fabric_lib.c | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/drivers/target/target_core_fabric_lib.c b/drivers/target/target_core_fabric_lib.c
index 2853b95b2c59..e15f5118b209 100644
--- a/drivers/target/target_core_fabric_lib.c
+++ b/drivers/target/target_core_fabric_lib.c
@@ -371,6 +371,17 @@ static bool iscsi_parse_pr_out_transport_id(
pr_err("Missing ISID in iSCSI Initiator port TransportID\n");
return false;
}
+ /*
+ * The conversion loop below only scans the ISID without
+ * ever terminating it, but the registration code reads it
+ * as a C string. With no NUL inside the TransportID,
+ * the reads run past the descriptor, and past the
+ * mapped buffer when the descriptor ends the buffer.
+ */
+ if (!memchr(p, '\0', buf + tid_len - p)) {
+ pr_err("Missing NUL terminator for ISID in iSCSI Initiator port TransportID\n");
+ return false;
+ }
*port_nexus_ptr = p;
/*
* Go ahead and do the lower case conversion of the received
--
2.43.7
next reply other threads:[~2026-10-26 4:46 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-26 4:46 Yuanhe Shu [this message]
2026-10-26 12:41 ` [PATCH v2] " Yuanhe Shu
[not found] ` <sashiko-outbox-184760@kernel.org>
2026-10-26 12:48 ` [PATCH] " Yuanhe Shu
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=20261026044632.1738901-1-xiangzao@linux.alibaba.com \
--to=xiangzao@linux.alibaba.com \
--cc=ddiss@suse.de \
--cc=hexlabsecurity@proton.me \
--cc=john.garry@linux.dev \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-scsi@vger.kernel.org \
--cc=mkp@kernel.org \
--cc=stable@vger.kernel.org \
--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®