[PATCH] scsi: target: iscsi: NUL-terminate login req_buf
Huihui Huang <[email protected]> Fri, 17 Jul 2026 00:44:07 +0800
| Newsgroups | org.kernel.vger.target-devel,org.kernel.vger.linux-scsi |
|---|---|
| Message-ID | <[email protected]> |
login->req_buf is a MAX_KEY_VALUE_PAIRS (8192) byte buffer that holds the
data segment of a received login PDU. iscsi_target_check_login_request()
rejects only payload_length > MAX_KEY_VALUE_PAIRS, so a payload of exactly
8192 bytes is accepted and fills req_buf completely, leaving no NUL
terminator (no padding is present because 8192 is four-byte aligned).
The security-phase text parser works on a kmemdup_nul() copy and is safe,
but the CHAP negotiation code consumes req_buf directly as a C string.
During the initial CHAP exchange, chap_check_algorithm() passes req_buf to
kstrdup(); during the subsequent CHAP exchange, convert_null_to_semi()
replaces embedded separators and extract_param() uses strstr() and
strlen_semi(). Both paths treat req_buf as a C string and therefore
require a terminating NUL within the allocated buffer.
A security-stage login request whose 8192-byte data segment begins with
"CHAP_A=" and contains no 0x00 byte therefore makes strlen() read past the
end of the allocation. This is reachable pre-authentication by a remote
initiator during CHAP negotiation.
Allocate one extra byte so a maximum-length data segment is followed by
a NUL terminator. In the socket receive path, also terminate at
payload_length so received padding bytes are not parsed as CHAP text.
Other login transports copy at most MAX_KEY_VALUE_PAIRS bytes into
req_buf, so the added final byte remains zero and bounds C-string scans.
Fixes: e48354ce078c ("iscsi-target: Add iSCSI fabric support for target v4.1")
Cc: [email protected]
Assisted-by: Claude:claude-opus-4-8
Signed-off-by: Huihui Huang <[email protected]>
---
drivers/target/iscsi/iscsi_target_login.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
Tested with KASAN using a temporary KUnit test that calls the static
chap_check_algorithm() on an 8192-byte buffer beginning with "CHAP_A=" and
containing no NUL. Two cases model req_buf before and after the change, in
one kernel:
tight (kmalloc(8192), no terminator = current req_buf):
BUG: KASAN: slab-out-of-bounds in strlen+0x23/0x40
kstrdup
chap_check_algorithm
plus_one (kzalloc(8192 + 1), byte 8192 == 0 = req_buf after this change):
ok, chap_check_algorithm returns cleanly, no KASAN report.
An unparsable CHAP_A algorithm returns CHAP_DIGEST_UNKNOWN, so the login
fails; the fix does not leave a malformed frame on a success path.
diff --git a/drivers/target/iscsi/iscsi_target_login.c b/drivers/target/iscsi/iscsi_target_login.c
index aafc94bcb635..417805cd62d7 100644
--- a/drivers/target/iscsi/iscsi_target_login.c
+++ b/drivers/target/iscsi/iscsi_target_login.c
@@ -47,7 +47,7 @@ static struct iscsi_login *iscsi_login_init_conn(struct iscsit_conn *conn)
login->conn = conn;
login->first_request = 1;
- login->req_buf = kzalloc(MAX_KEY_VALUE_PAIRS, GFP_KERNEL);
+ login->req_buf = kzalloc(MAX_KEY_VALUE_PAIRS + 1, GFP_KERNEL);
if (!login->req_buf) {
pr_err("Unable to allocate memory for response buffer.\n");
goto out_login;
@@ -966,6 +966,7 @@ int iscsit_get_login_rx(struct iscsit_conn *conn, struct iscsi_login *login)
payload_length + padding) < 0)
return -1;
+ login->req_buf[payload_length] = '\0';
return 0;
}
base-commit: e166bafc483e927150cb9b5f286c9191ea0df84e
--
2.50.1