[PATCH v5 3/3] RDMA/srpt: Prevent uninitialized read buffer disclosure
From: Yong Liu
Date: Fri Nov 13 2026 - 09:50:14 EST
SRPT allocates read buffers and creates RDMA contexts from the initiator's
descriptors before parsing the CDB. When target core shortens
cmd->data_length, a backend such as rd_mcp fills only the shorter length,
but the prebuilt RDMA transfer still sends the full buffer. This can
disclose stale target kernel memory to a remote initiator with access to
the LUN.
Reject indirect descriptor tables whose direct descriptor lengths do not
sum to the advertised total, and log the mismatch before allocating RDMA
contexts. Save the original buffer length and zero the tail beyond
cmd->data_length through the chained command scatterlist before posting
RDMA transfers. This applies to both data and control READ commands.
The issue was discovered by Qihoo 360's Tulongfeng multi-agent system.
Fixes: b99f8e4d7bcd ("IB/srpt: convert to the generic RDMA READ/WRITE API")
Cc: stable@xxxxxxxxxxxxxxx
Suggested-by: Bart Van Assche <bvanassche@xxxxxxx>
Signed-off-by: Yong Liu <pkfxxxing@xxxxxxxxx>
---
drivers/infiniband/ulp/srpt/ib_srpt.c | 17 +++++++++++++++++
drivers/infiniband/ulp/srpt/ib_srpt.h | 2 ++
2 files changed, 19 insertions(+)
diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.c b/drivers/infiniband/ulp/srpt/ib_srpt.c
index 127f256c6e..fc530ddf48 100644
--- a/drivers/infiniband/ulp/srpt/ib_srpt.c
+++ b/drivers/infiniband/ulp/srpt/ib_srpt.c
@@ -1115,8 +1115,10 @@ static int srpt_get_desc_tbl(struct srpt_recv_ioctx *recv_ioctx,
} else if (((srp_cmd->buf_fmt & 0xf) == SRP_DATA_DESC_INDIRECT) ||
((srp_cmd->buf_fmt >> 4) == SRP_DATA_DESC_INDIRECT)) {
struct srp_indirect_buf *idb = srpt_get_desc_buf(srp_cmd);
+ u64 total_len = 0;
int nbufs = be32_to_cpu(idb->table_desc.len) /
sizeof(struct srp_direct_buf);
+ int i;
if (nbufs >
(srp_cmd->data_out_desc_cnt + srp_cmd->data_in_desc_cnt)) {
@@ -1128,6 +1130,14 @@ static int srpt_get_desc_tbl(struct srpt_recv_ioctx *recv_ioctx,
return -EINVAL;
}
+ for (i = 0; i < nbufs; i++)
+ total_len += be32_to_cpu(idb->desc_list[i].len);
+ if (total_len != be32_to_cpu(idb->len)) {
+ pr_err("SRP descriptor lengths total %llu does not match advertised length %u\n",
+ total_len, be32_to_cpu(idb->len));
+ return -EINVAL;
+ }
+
*data_len = be32_to_cpu(idb->len);
return srpt_alloc_rw_ctxs(ioctx, idb->desc_list, nbufs,
sg, sg_cnt);
@@ -1304,6 +1314,7 @@ static struct srpt_send_ioctx *srpt_get_send_ioctx(struct srpt_rdma_ch *ch)
WARN_ON_ONCE(ioctx->recv_ioctx);
ioctx->n_rdma = 0;
ioctx->n_rw_ctx = 0;
+ ioctx->buf_len = 0;
ioctx->queue_status_only = false;
/*
* transport_init_se_cmd() does not initialize all fields, so do it
@@ -1607,6 +1618,7 @@ static void srpt_handle_cmd(struct srpt_rdma_ch *ch,
goto busy;
}
+ send_ioctx->buf_len = data_len;
rc = target_init_cmd(cmd, ch->sess, &send_ioctx->sense_data[0],
scsilun_to_int(&srp_cmd->lun), data_len,
cmd->sam_task_attr, dir, TARGET_SCF_ACK_KREF);
@@ -2914,6 +2926,11 @@ static void srpt_queue_response(struct se_cmd *cmd)
if (ioctx->cmd.data_direction == DMA_FROM_DEVICE &&
ioctx->cmd.data_length &&
!ioctx->queue_status_only) {
+ if (ioctx->buf_len > cmd->data_length)
+ sg_zero_buffer(cmd->t_data_sg, cmd->t_data_nents,
+ ioctx->buf_len - cmd->data_length,
+ cmd->data_length);
+
for (i = ioctx->n_rw_ctx - 1; i >= 0; i--) {
struct srpt_rw_ctx *ctx = &ioctx->rw_ctxs[i];
diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.h b/drivers/infiniband/ulp/srpt/ib_srpt.h
index 506c11b843..78bba74148 100644
--- a/drivers/infiniband/ulp/srpt/ib_srpt.h
+++ b/drivers/infiniband/ulp/srpt/ib_srpt.h
@@ -204,6 +204,7 @@ struct srpt_rw_ctx {
* @rdma_cqe: RDMA completion queue element.
* @state: I/O context state.
* @cmd: Target core command data structure.
+ * @buf_len: Original SRP data buffer length.
* @sense_data: SCSI sense data.
* @n_rdma: Number of work requests needed to transfer this ioctx.
* @n_rw_ctx: Size of rw_ctxs array.
@@ -223,6 +224,7 @@ struct srpt_send_ioctx {
struct ib_cqe rdma_cqe;
enum srpt_command_state state;
struct se_cmd cmd;
+ u32 buf_len;
u8 n_rdma;
u8 n_rw_ctx;
bool queue_status_only;
--
2.43.0