[PATCH] scsi: qedi: fix OOB read in login/text response completion
From: Henry Martin
Date: Tue Oct 27 2026 - 11:14:31 EST
qedi_process_text_resp() and qedi_process_login_resp() take the payload
length straight from the CQE field (hdr_second_dword &
ISCSI_{LOGIN,TEXT}_RESPONSE_HDR_DATA_SEG_LEN_MASK, 24 bits) written
back by the adapter, without any bounds check:
pld_len = cqe_text_response->hdr_second_dword &
ISCSI_TEXT_RESPONSE_HDR_DATA_SEG_LEN_MASK;
qedi_conn->gen_pdu.resp_wr_ptr = qedi_conn->gen_pdu.resp_buf + pld_len;
...
__iscsi_complete_pdu(conn, ..., qedi_conn->gen_pdu.resp_buf,
(qedi_conn->gen_pdu.resp_wr_ptr -
qedi_conn->gen_pdu.resp_buf));
resp_buf is an 8192-byte buffer (qedi_iscsi.c). A CQE whose data
segment length exceeds the buffer makes resp_wr_ptr point past its end,
and the fabricated length is then passed to __iscsi_complete_pdu() as
the response buffer size: an out-of-bounds read of the buffer (and
beyond) delivered to the iscsi userspace daemon over the iscsi_recv_pdu
netlink unicast.
Clamp the payload length to the response buffer size before computing
the write pointer, in both the login and text response handlers.
This issue was discovered by Tencent CodeBuddy Security.
Fixes: ace7f46ba5fd ("scsi: qedi: Add QLogic FastLinQ offload iSCSI driver framework.")
Cc: stable@xxxxxxxxxxxxxxx
Signed-off-by: Henry Martin <bsdhenrymartin@xxxxxxxxx>
---
drivers/scsi/qedi/qedi_fw.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/drivers/scsi/qedi/qedi_fw.c b/drivers/scsi/qedi/qedi_fw.c
index 854efa4f61d87..24724fcba6571 100644
--- a/drivers/scsi/qedi/qedi_fw.c
+++ b/drivers/scsi/qedi/qedi_fw.c
@@ -115,6 +115,8 @@ static void qedi_process_text_resp(struct qedi_ctx *qedi,
pld_len = cqe_text_response->hdr_second_dword &
ISCSI_TEXT_RESPONSE_HDR_DATA_SEG_LEN_MASK;
+ if (pld_len > qedi_conn->gen_pdu.resp_buf_size)
+ pld_len = qedi_conn->gen_pdu.resp_buf_size;
qedi_conn->gen_pdu.resp_wr_ptr = qedi_conn->gen_pdu.resp_buf + pld_len;
memset(task_ctx, '\0', sizeof(*task_ctx));
@@ -292,6 +294,8 @@ static void qedi_process_login_resp(struct qedi_ctx *qedi,
resp_hdr_ptr->status_detail = cqe_login_response->status_detail;
pld_len = cqe_login_response->hdr_second_dword &
ISCSI_LOGIN_RESPONSE_HDR_DATA_SEG_LEN_MASK;
+ if (pld_len > qedi_conn->gen_pdu.resp_buf_size)
+ pld_len = qedi_conn->gen_pdu.resp_buf_size;
qedi_conn->gen_pdu.resp_wr_ptr = qedi_conn->gen_pdu.resp_buf + pld_len;
spin_lock(&qedi_conn->list_lock);
--
2.43.7