[PATCH] scsi: target: iscsi: Reject Extended CDB AHS when CDB size exceeds AHS length
[email protected] Thu, 6 Aug 2026 13:48:20 +0800
| Newsgroups | gmane.linux.scsi.target.devel,gmane.linux.scsi |
|---|---|
| Message-ID | <[email protected]> |
From: Cao Guanghui <[email protected]> In iscsit_setup_scsi_cmd(), the Extended CDB AHS path allocates the CDB buffer using only the iSCSI AHS-declared length. The buffer is then handed to target_cmd_init_cdb(), which re-derives the CDB length from the SCSI opcode via scsi_command_size(). For a VARIABLE_LENGTH_CMD (0x7f) the size is cdb[7] + 8, where both cdb[0] and cdb[7] come verbatim from the initiator-controlled hdr->cdb. The AHS-declared length and the opcode-declared length are never cross-checked. An initiator can thus advertise a minimal AHS (ahslength = 1, which passes the !ahslength and ahslength > hlength*4 - 3 checks added by commit 2f3835771dff ("scsi: target: iscsi: reject invalid size Extended CDB AHS") while setting cdb[0]=0x7f and cdb[7]=252. This yields a 16-byte kmalloc but scsi_command_size() returns 260, so target_cmd_init_cdb() reads 260 bytes from a 16-byte heap object, a heap out-of-bounds read. The leaked bytes are later parsed as the CDB and can be indirectly observed by the initiator through sense data and responses. commit 2f3835771dff ("scsi: target: iscsi: reject invalid size Extended CDB AHS") fixed the zero-length ahslength overflows and the AHS-buffer overread, but did not cover the orthogonal "allocation size vs. opcode-declared size" path. Reject the command when the opcode-declared CDB size exceeds the AHS-provided length, before the kmalloc. Fixes: 8f1f7d297bce ("scsi: target: iscsi: Add support for extended CDB AHS") Signed-off-by: Cao Guanghui <[email protected]> --- drivers/target/iscsi/iscsi_target.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c index 62ada3a52210..e3e9254df960 100644 --- a/drivers/target/iscsi/iscsi_target.c +++ b/drivers/target/iscsi/iscsi_target.c @@ -1124,6 +1124,19 @@ int iscsit_setup_scsi_cmd(struct iscsit_conn *conn, struct iscsit_cmd *cmd, cdb_length = ahslength - 1 + ISCSI_CDB_SIZE; + /* + * The CDB buffer is later re-parsed by scsi_command_size() based + * on its opcode, which may claim a length larger than the AHS + * provided. Reject such a mismatch before allocating to avoid + * an out-of-bounds read of the CDB buffer in target_cmd_init_cdb(). + */ + if (scsi_command_size(hdr->cdb) > cdb_length) { + pr_err("Extended CDB AHS: SCSI command size %u exceeds AHS-provided CDB length %u, protocol error.\n", + scsi_command_size(hdr->cdb), cdb_length); + return iscsit_add_reject_cmd(cmd, + ISCSI_REASON_PROTOCOL_ERROR, buf); + } + cdb = kmalloc(cdb_length, GFP_KERNEL); if (cdb == NULL) return iscsit_add_reject_cmd(cmd, -- 2.34.1