Skip to contentSkip to conversation

RDMA/rtrs-clt: Validate peer-supplied IO completion msg_id

PATCH Applied Quanye Yang 4 participants 4 messages Sep 23 – Sep 29

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

PATCH 1/1 RDMA/rtrs-clt: Validate peer-supplied IO completion msg_id

process_io_rsp() indexes clt_path->reqs[] with the 19-bit msg_id taken from a WRITE_WITH_IMM immediate. That value is chosen by the peer. The only check was WARN_ON(msg_id >= queue_depth), which still lets a completion run after free_path_reqs() has set reqs to NULL, or against a slot whose FRWR is already gone. Either path dereferences req->mr and can GPF; KASAN reports a null-ptr-deref at offsetof(struct rtrs_clt_io_req, mr).

Treat a missing reqs array, an out-of-range msg_id, or a req without an MR as a protocol error and recover the connection.

---
 drivers/infiniband/ulp/rtrs/rtrs-clt.c | 21 ++++++++++++++++-----
 1 file changed, 16 insertions(+), 5 deletions(-)
drivers/infiniband/ulp/rtrs/rtrs-clt.c +16 -5
index eac38b57b00d..f8d3c6f37e3e 100644
@@ -489,18 +489,22 @@ static int rtrs_post_send_rdma(struct rtrs_clt_con *con,
 					    imm, flags, wr, NULL);
 }
 
-static void process_io_rsp(struct rtrs_clt_path *clt_path, u32 msg_id,
+static bool process_io_rsp(struct rtrs_clt_path *clt_path, u32 msg_id,
 			   s16 errno, bool w_inval)
 {
 	struct rtrs_clt_io_req *req;
 
-	if (WARN_ON(msg_id >= clt_path->queue_depth))
-		return;
+	if (!clt_path->reqs || msg_id >= clt_path->queue_depth)
+		return false;
 
 	req = &clt_path->reqs[msg_id];
+	if (!req->mr)
+		return false;
+
 	/* Drop need_inv if server responded with send with invalidation */
 	req->mr->need_inval &= !w_inval;
 	complete_rdma_req(req, errno, true, false);
+	return true;
 }
 
 static void rtrs_clt_recv_done(struct rtrs_clt_con *con, struct ib_wc *wc)
@@ -562,7 +566,8 @@ static void rtrs_clt_rkey_rsp_done(struct rtrs_clt_con *con, struct ib_wc *wc)
 		if (WARN_ON(buf_id != msg_id))
 			goto out;
 		clt_path->rbufs[buf_id].rkey = le32_to_cpu(msg->rkey);
-		process_io_rsp(clt_path, msg_id, err, w_inval);
+		if (!process_io_rsp(clt_path, msg_id, err, w_inval))
+			goto out;
 	}
 	ib_dma_sync_single_for_device(clt_path->s.dev->ib_dev, iu->dma_addr,
 				      iu->size, DMA_FROM_DEVICE);
@@ -634,7 +639,13 @@ static void rtrs_clt_rdma_done(struct ib_cq *cq, struct ib_wc *wc)
 			w_inval = (imm_type == RTRS_IO_RSP_W_INV_IMM);
 			rtrs_from_io_rsp_imm(imm_payload, &msg_id, &err);
 
-			process_io_rsp(clt_path, msg_id, err, w_inval);
+			if (!process_io_rsp(clt_path, msg_id, err, w_inval)) {
+				rtrs_err(clt_path->clt,
+					 "Invalid IO rsp: msg_id %u queue_depth %zu\n",
+					 msg_id, clt_path->queue_depth);
+				rtrs_rdma_error_recovery(con);
+				return;
+			}
 		} else if (imm_type == RTRS_HB_MSG_IMM) {
 			WARN_ON(con->c.cid);
 			rtrs_send_hb_ack(&clt_path->s);

---
base-commit: 93f51579e7df248780214094418f205253383cc5
change-id: 20260923-rtrs-warning-inrtrs-clt-rdma-done-3a72d73550b1

Best regards,

Signature · 1 line
Quanye Yang <[email protected]>
#1 lore raw
Sashiko has reviewed this patch and found no issues. It looks great!
Quoted 10 lines

From: Quanye Yang <[email protected]>

process_io_rsp() indexes clt_path->reqs[] with the 19-bit msg_id taken from a WRITE_WITH_IMM immediate. That value is chosen by the peer. The only check was WARN_ON(msg_id >= queue_depth), which still lets a completion run after free_path_reqs() has set reqs to NULL, or against a slot whose FRWR is already gone. Either path dereferences req->mr and can GPF; KASAN reports a null-ptr-deref at offsetof(struct rtrs_clt_io_req, mr).

Quoted 7 lines

Treat a missing reqs array, an out-of-range msg_id, or a req without an MR as a protocol error and recover the connection.

Sashiko has reviewed this patch and found no issues. It looks great!

Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/20260923-rtrs-warning-inrtrs-clt-rdma-done-v1-1-0827a9a77c0b@proton.me?part=1
Reviewed-by on v1 1/1
#2 lore raw
In reply to Quanye Yang
Quoted 11 lines · On Wed, Sep 23, 2026 at 12:52 PM Quanye Yang via B4 Relay…

From: Quanye Yang <[email protected]>

process_io_rsp() indexes clt_path->reqs[] with the 19-bit msg_id taken from a WRITE_WITH_IMM immediate. That value is chosen by the peer. The only check was WARN_ON(msg_id >= queue_depth), which still lets a completion run after free_path_reqs() has set reqs to NULL, or against a slot whose FRWR is already gone. Either path dereferences req->mr and can GPF; KASAN reports a null-ptr-deref at offsetof(struct rtrs_clt_io_req, mr).

Quoted 7 lines

Treat a missing reqs array, an out-of-range msg_id, or a req without an MR as a protocol error and recover the connection.

lgtm, thx!

Quoted 69 lines
---
 drivers/infiniband/ulp/rtrs/rtrs-clt.c | 21 ++++++++++++++++-----
 1 file changed, 16 insertions(+), 5 deletions(-)
drivers/infiniband/ulp/rtrs/rtrs-clt.c +16 -6
index eac38b57b00d..f8d3c6f37e3e 100644
@@ -489,18 +489,22 @@ static int rtrs_post_send_rdma(struct rtrs_clt_con *con,
                                            imm, flags, wr, NULL);
 }
 
-static void process_io_rsp(struct rtrs_clt_path *clt_path, u32 msg_id,
+static bool process_io_rsp(struct rtrs_clt_path *clt_path, u32 msg_id,
                           s16 errno, bool w_inval)
 {
        struct rtrs_clt_io_req *req;
 
-       if (WARN_ON(msg_id >= clt_path->queue_depth))
-               return;
+       if (!clt_path->reqs || msg_id >= clt_path->queue_depth)
+               return false;
 
        req = &clt_path->reqs[msg_id];
+       if (!req->mr)
+               return false;
+
        /* Drop need_inv if server responded with send with invalidation */
        req->mr->need_inval &= !w_inval;
        complete_rdma_req(req, errno, true, false);
+       return true;
 }
 
 static void rtrs_clt_recv_done(struct rtrs_clt_con *con, struct ib_wc *wc)
@@ -562,7 +566,8 @@ static void rtrs_clt_rkey_rsp_done(struct rtrs_clt_con *con, struct ib_wc *wc)
                if (WARN_ON(buf_id != msg_id))
                        goto out;
                clt_path->rbufs[buf_id].rkey = le32_to_cpu(msg->rkey);
-               process_io_rsp(clt_path, msg_id, err, w_inval);
+               if (!process_io_rsp(clt_path, msg_id, err, w_inval))
+                       goto out;
        }
        ib_dma_sync_single_for_device(clt_path->s.dev->ib_dev, iu->dma_addr,
                                      iu->size, DMA_FROM_DEVICE);
@@ -634,7 +639,13 @@ static void rtrs_clt_rdma_done(struct ib_cq *cq, struct ib_wc *wc)
                        w_inval = (imm_type == RTRS_IO_RSP_W_INV_IMM);
                        rtrs_from_io_rsp_imm(imm_payload, &msg_id, &err);
 
-                       process_io_rsp(clt_path, msg_id, err, w_inval);
+                       if (!process_io_rsp(clt_path, msg_id, err, w_inval)) {
+                               rtrs_err(clt_path->clt,
+                                        "Invalid IO rsp: msg_id %u queue_depth %zu\n",
+                                        msg_id, clt_path->queue_depth);
+                               rtrs_rdma_error_recovery(con);
+                               return;
+                       }
                } else if (imm_type == RTRS_HB_MSG_IMM) {
                        WARN_ON(con->c.cid);
                        rtrs_send_hb_ack(&clt_path->s);
 
---

base-commit: 93f51579e7df248780214094418f205253383cc5
change-id: 20260923-rtrs-warning-inrtrs-clt-rdma-done-3a72d73550b1

Best regards,
--
Quanye Yang <[email protected]>

maintainer Applied
#3 lore raw
In reply to Quanye Yang
Quoted 13 lines · Quanye Yang

From: Quanye Yang <[email protected]>

process_io_rsp() indexes clt_path->reqs[] with the 19-bit msg_id taken from a WRITE_WITH_IMM immediate. That value is chosen by the peer. The only check was WARN_ON(msg_id >= queue_depth), which still lets a completion run after free_path_reqs() has set reqs to NULL, or against a slot whose FRWR is already gone. Either path dereferences req->mr and can GPF; KASAN reports a null-ptr-deref at offsetof(struct rtrs_clt_io_req, mr).

Treat a missing reqs array, an out-of-range msg_id, or a req without an MR as a protocol error and recover the connection.

Quoted 8 lines
---
 drivers/infiniband/ulp/rtrs/rtrs-clt.c | 21 ++++++++++++++++-----
 1 file changed, 16 insertions(+), 5 deletions(-)

Applied to for-next, thanks

Jason