Skip to contentSkip to conversation

RDMA/rtrs-srv: Fix integer underflow in process_read and process_write

PATCH Applied Aurelien DESBRIERES 3 participants 3 messages Jun 8

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

PATCH 1/1 RDMA/rtrs-srv: Fix integer underflow in process_read and process_write

usr_len is read from a network-supplied message field (le16_to_cpu) and used to compute data_len = off - usr_len without validating that usr_len <= off. A malicious RDMA client can send usr_len > off causing an integer underflow, resulting in data_len wrapping to a huge size_t value which is then passed to the rdma_ev callback as a memory length, leading to out-of-bounds memory access.

Fix by reading and validating usr_len <= off before rtrs_srv_get_ops_ids() in both process_read() and process_write(), ensuring the early return path acquires no reference and has no resource leak.

---
 drivers/infiniband/ulp/rtrs/rtrs-srv.c | 12 ++++++++++--
 1 file changed, 10 insertions(+), 2 deletions(-)
drivers/infiniband/ulp/rtrs/rtrs-srv.c +10 -2
index 6482ad859..f2fd80c8a 100644
@@ -1059,6 +1059,11 @@ static void process_read(struct rtrs_srv_con *con,
 			    "Processing read request failed, invalid message\n");
 		return;
 	}
+	usr_len = le16_to_cpu(msg->usr_len);
+	if (usr_len > off) {
+		pr_debug("rtrs-srv: Invalid usr_len %zu > off %u\n", usr_len, off);
+		return;
+	}
 	rtrs_srv_get_ops_ids(srv_path);
 	rtrs_srv_update_rdma_stats(srv_path->stats, off, READ);
 	id = srv_path->ops_ids[buf_id];
@@ -1066,7 +1071,6 @@ static void process_read(struct rtrs_srv_con *con,
 	id->dir		= READ;
 	id->msg_id	= buf_id;
 	id->rd_msg	= msg;
-	usr_len = le16_to_cpu(msg->usr_len);
 	data_len = off - usr_len;
 	data = page_address(srv->chunks[buf_id]);
 	ret = ctx->ops.rdma_ev(srv->priv, id, data, data_len,
@@ -1112,6 +1116,11 @@ static void process_write(struct rtrs_srv_con *con,
 			     rtrs_srv_state_str(srv_path->state));
 		return;
 	}
+	usr_len = le16_to_cpu(req->usr_len);
+	if (usr_len > off) {
+		pr_debug("rtrs-srv: Invalid usr_len %zu > off %u\n", usr_len, off);
+		return;
+	}
 	rtrs_srv_get_ops_ids(srv_path);
 	rtrs_srv_update_rdma_stats(srv_path->stats, off, WRITE);
 	id = srv_path->ops_ids[buf_id];
@@ -1119,7 +1128,6 @@ static void process_write(struct rtrs_srv_con *con,
 	id->dir    = WRITE;
 	id->msg_id = buf_id;
 
-	usr_len = le16_to_cpu(req->usr_len);
 	data_len = off - usr_len;
 	data = page_address(srv->chunks[buf_id]);
 	ret = ctx->ops.rdma_ev(srv->priv, id, data, data_len,
Signature · 1 line
2.43.0
maintainer Acked-by on v1 1/1
#1 lore raw
Quoted 8 lines · Aurelien DESBRIERES

usr_len is read from a network-supplied message field (le16_to_cpu) and used to compute data_len = off - usr_len without validating that usr_len <= off. A malicious RDMA client can send usr_len > off causing an integer underflow, resulting in data_len wrapping to a huge size_t value which is then passed to the rdma_ev callback as a memory length, leading to out-of-bounds memory access.

Quoted 8 lines

Fix by reading and validating usr_len <= off before rtrs_srv_get_ops_ids() in both process_read() and process_write(), ensuring the early return path acquires no reference and has no resource leak.

Quoted 51 lines
---
 drivers/infiniband/ulp/rtrs/rtrs-srv.c | 12 ++++++++++--
 1 file changed, 10 insertions(+), 2 deletions(-)
drivers/infiniband/ulp/rtrs/rtrs-srv.c +10 -3
index 6482ad859..f2fd80c8a 100644
@@ -1059,6 +1059,11 @@ static void process_read(struct rtrs_srv_con *con,
                            "Processing read request failed, invalid message\n");
                return;
        }
+       usr_len = le16_to_cpu(msg->usr_len);
+       if (usr_len > off) {
+               pr_debug("rtrs-srv: Invalid usr_len %zu > off %u\n", usr_len, off);
+               return;
+       }
        rtrs_srv_get_ops_ids(srv_path);
        rtrs_srv_update_rdma_stats(srv_path->stats, off, READ);
        id = srv_path->ops_ids[buf_id];
@@ -1066,7 +1071,6 @@ static void process_read(struct rtrs_srv_con *con,
        id->dir         = READ;
        id->msg_id      = buf_id;
        id->rd_msg      = msg;
-       usr_len = le16_to_cpu(msg->usr_len);
        data_len = off - usr_len;
        data = page_address(srv->chunks[buf_id]);
        ret = ctx->ops.rdma_ev(srv->priv, id, data, data_len,
@@ -1112,6 +1116,11 @@ static void process_write(struct rtrs_srv_con *con,
                             rtrs_srv_state_str(srv_path->state));
                return;
        }
+       usr_len = le16_to_cpu(req->usr_len);
+       if (usr_len > off) {
+               pr_debug("rtrs-srv: Invalid usr_len %zu > off %u\n", usr_len, off);
+               return;
+       }
        rtrs_srv_get_ops_ids(srv_path);
        rtrs_srv_update_rdma_stats(srv_path->stats, off, WRITE);
        id = srv_path->ops_ids[buf_id];
@@ -1119,7 +1128,6 @@ static void process_write(struct rtrs_srv_con *con,
        id->dir    = WRITE;
        id->msg_id = buf_id;
 
-       usr_len = le16_to_cpu(req->usr_len);
        data_len = off - usr_len;
        data = page_address(srv->chunks[buf_id]);
        ret = ctx->ops.rdma_ev(srv->priv, id, data, data_len,
--

2.43.0

maintainer Applied
#2 lore raw
In reply to Aurelien DESBRIERES
Quoted 11 lines · Aurelien DESBRIERES

usr_len is read from a network-supplied message field (le16_to_cpu) and used to compute data_len = off - usr_len without validating that usr_len <= off. A malicious RDMA client can send usr_len > off causing an integer underflow, resulting in data_len wrapping to a huge size_t value which is then passed to the rdma_ev callback as a memory length, leading to out-of-bounds memory access.

Fix by reading and validating usr_len <= off before rtrs_srv_get_ops_ids() in both process_read() and process_write(), ensuring the early return path acquires no reference and has no resource leak.

Quoted 8 lines
---
 drivers/infiniband/ulp/rtrs/rtrs-srv.c | 12 ++++++++++--
 1 file changed, 10 insertions(+), 2 deletions(-)

Applied, thanks

Jason