[PATCH] RDMA/rxe: enforce memory window ranges

From: sungbyeongchan

Date: Tue Oct 06 2026 - 14:52:09 EST


RXE records the address and length authorized by an MW bind, but the
responder does not compare a remote request with that interval. After
validating the MW key, PD, QP, access, and state, check_rkey() selects the
backing MR and applies only the broader MR range check.

A peer with a valid rkey for a 64-byte type-2 MW could consequently READ
and WRITE another address in the same 4096-byte backing MR. In two runs,
an eight-byte READ returned the exact nondelegated sentinel and an
eight-byte WRITE replaced it with the peer's chosen bytes. In-window
operations succeeded and a request crossing the backing-MR end was
rejected.

Check the complete request extent against the MW interval before selecting
the backing MR. Use subtraction-form comparisons to avoid addition overflow
and handle zero-based MWs relative to address zero.

The fixed kernel rejects outside-window READ and WRITE with remote-access
errors while preserving normal in-window READ and WRITE.

The demonstrated impact is access to registered userspace memory outside
the delegated MW. Kernel memory access, code execution, and privilege
escalation were not demonstrated.

Fixes: cdd0b85675ae ("RDMA/rxe: Implement memory access through MWs")
Cc: stable@xxxxxxxxxxxxxxx
Assisted-by: LLM
Signed-off-by: sungbyeongchan <tjdqudcks0424@xxxxxxxxx>
---
drivers/infiniband/sw/rxe/rxe_resp.c | 10 ++++++++++
1 file changed, 10 insertions(+)

diff --git a/drivers/infiniband/sw/rxe/rxe_resp.c b/drivers/infiniband/sw/rxe/rxe_resp.c
index 02b16e2b49b8f..01eb111f81ca6 100644
--- a/drivers/infiniband/sw/rxe/rxe_resp.c
+++ b/drivers/infiniband/sw/rxe/rxe_resp.c
@@ -520,6 +520,8 @@ static enum resp_states check_rkey(struct rxe_qp *qp,
pktlen = payload_size(pkt);

if (rkey_is_mw(rkey)) {
+ u64 mw_start;
+
mw = rxe_lookup_mw(qp, access, rkey);
if (!mw) {
rxe_dbg_qp(qp, "no MW matches rkey %#x\n", rkey);
@@ -527,6 +529,14 @@ static enum resp_states check_rkey(struct rxe_qp *qp,
goto err;
}

+ mw_start = (mw->access & IB_ZERO_BASED) ? 0 : mw->addr;
+ if (unlikely(va < mw_start || resid > mw->length ||
+ va - mw_start > mw->length - resid)) {
+ rxe_dbg_qp(qp, "request outside MW range\n");
+ state = get_rkey_violation_state(pkt);
+ goto err;
+ }
+
mr = mw->mr;
if (!mr) {
rxe_dbg_qp(qp, "MW doesn't have an MR\n");
--
2.43.0