[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