* [PATCH 0/4] RDMA/rxe: Fix u64 iova-overflow family in MR/ODP/RESP/MW paths
@ 2026-05-21 19:44 Tymbark7372
2026-05-21 19:44 ` [PATCH 1/4] RDMA/rxe: Fix u64 iova+length overflow in mr_check_range Tymbark7372
` (4 more replies)
0 siblings, 5 replies; 9+ messages in thread
From: Tymbark7372 @ 2026-05-21 19:44 UTC (permalink / raw)
To: linux-rdma; +Cc: zyjzyj2000, jgg, leonro, stable, Tymbark7372
This patchset fixes a family of u64 overflow bugs in the rxe Soft-RoCE
driver. All four sites share one root cause: addition of an
attacker-influenced iova/addr (u64) with an attacker-influenced
length/resid (size_t/u32/int promoted to u64), without overflow
check, leading to an OOB read/write primitive in the rxe responder
workqueue.
I originally reported these to security@kernel.org. Jason Gunthorpe
confirmed that rxe and siw are development-only drivers without
embargo handling and asked me to send patches publicly, so I'm
posting here per his direction. security@kernel.org is intentionally
not in Cc per Jason's instruction.
This is a resend of the patches I sent earlier today as attachments.
Zhu Yanjun pointed out attachments aren't the convention and asked
for inline format via git send-email.
Patches:
1/4: rxe_mr.c mr_check_range
The USER/MEM_REG case computes iova + length and compares to
mr->ibmr.iova + mr->ibmr.length. Both additions wrap in u64.
Use check_add_overflow() for both ends.
2/4: rxe_odp.c rxe_check_pagefault
Loop condition addr < iova + length wraps when iova is near
U64_MAX and length is positive. Compute iova_end with
check_add_overflow() once and use it in the loop condition.
3/4: rxe_resp.c duplicate_request
Third clause iova + resid > res->read.va_org + res->read.length
has u64 wrap on both sides. Use check_add_overflow() for both
ends. (Site A in check_rkey, also in rxe_resp.c, calls into
mr_check_range and is closed by patch 1.)
4/4: rxe_mw.c rxe_check_bind_mw
Same wrap class as patch 1. Found by sibling-site grep; not on
the OOB-write path of the three primary bugs but a
structurally-identical u64 wrap that would let an attacker bind
a memory window outside its parent MR's range.
Verification:
Each of the three primary sibling triggers (patches 1, 2, 3) has been
exercised on v7.1.0-rc3 + KASAN in QEMU as the OOB-write case.
Patches 1 and 3 produce a single-page-fault Oops in rxe_mr_copy after
the wrap. Patch 2 produces a single-page-fault Oops in
rxe_odp_mr_copy. All three are triggered by a single ibv_post_send
from an unprivileged local user with /dev/infiniband/uverbs0 open.
A working LPE exploit demonstrated end-to-end privilege escalation
via the rxe_odp path under the verification config (KASAN dev-build,
selinux=0, nokaslr). Full PoC and writeup were attached to the
original security@kernel.org submission.
After applying all four patches, the same triggers no longer fire;
the wrap checks correctly reject the attacker iova. Re-tested in the
same QEMU+KASAN configuration.
The trigger PoCs are simple libibverbs programs (one per sibling)
that I am happy to provide on request.
Fixes / stable:
1/4: Fixes 8700e3e7c485 ("Soft RoCE driver"), v4.8+
2/4: Fixes 2fae67ab63db ("RDMA/rxe: Add support for Send/Recv/Write/Read with ODP"), v6.15+
3/4: Fixes 8700e3e7c485 ("Soft RoCE driver"), v4.8+
4/4: Fixes 8700e3e7c485 ("Soft RoCE driver"), v4.8+
Pre-f04d5b3d916c LTS branches carry the older wrap form
iova > mr->ibmr.iova + mr->ibmr.length - length
instead of the current `iova + length > ...` shape. Patches 1, 3, 4
will need a backport variant for those branches; I can provide on
request.
Tymbark7372 (4):
RDMA/rxe: Fix u64 iova+length overflow in mr_check_range
RDMA/rxe: Fix u64 iova+length overflow in rxe_check_pagefault
RDMA/rxe: Fix u64 iova+resid overflow in duplicate_request
RDMA/rxe: Fix u64 addr+length overflow in rxe_check_bind_mw
drivers/infiniband/sw/rxe/rxe_mr.c | 12 +++++++++---
drivers/infiniband/sw/rxe/rxe_odp.c | 10 ++++++++--
drivers/infiniband/sw/rxe/rxe_resp.c | 11 ++++++++---
drivers/infiniband/sw/rxe/rxe_mw.c | 11 ++++++++---
4 files changed, 33 insertions(+), 11 deletions(-)
--
2.43.0
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH 1/4] RDMA/rxe: Fix u64 iova+length overflow in mr_check_range
2026-05-21 19:44 [PATCH 0/4] RDMA/rxe: Fix u64 iova-overflow family in MR/ODP/RESP/MW paths Tymbark7372
@ 2026-05-21 19:44 ` Tymbark7372
2026-05-22 4:44 ` Greg KH
2026-05-21 19:44 ` [PATCH 2/4] RDMA/rxe: Fix u64 iova+length overflow in rxe_check_pagefault Tymbark7372
` (3 subsequent siblings)
4 siblings, 1 reply; 9+ messages in thread
From: Tymbark7372 @ 2026-05-21 19:44 UTC (permalink / raw)
To: linux-rdma; +Cc: zyjzyj2000, jgg, leonro, stable, Tymbark7372
In mr_check_range(), the IB_MR_TYPE_USER and IB_MR_TYPE_MEM_REG case
computes both iova + length and mr->ibmr.iova + mr->ibmr.length without
overflow check. Both iova (u64) and length (size_t) are 64-bit on
64-bit platforms. An attacker setting iova = 0xFFFFFFFFFFFFFC00 and
length = 0x400 wraps the sum to 0, so the bound check
"iova + length > mr->ibmr.iova + mr->ibmr.length" passes.
After the bypass, rxe_mr_iova_to_index() computes a huge index value;
WARN_ON(idx >= mr->nbuf) fires but does not abort, and
rxe_mr_copy_xarray() then dereferences page_info[huge_idx], an
attacker-controlled out-of-bounds slot. In the RXE_TO_MR_OBJ
direction this becomes an OOB write of attacker payload bytes through
info->page + info->offset.
Use check_add_overflow() on both ends to reject any iova/length pair
that wraps. Also explicitly scope the local declarations introduced
by the helper variables.
Reachable from any unprivileged local process with
/dev/infiniband/uverbs0 open (world-rw on distros that ship the
rdma-core udev rules) and from an unauthenticated remote peer over
UDP/4791 (RoCEv2) when the target rkey/QPN are known. Reproduced on
v7.1.0-rc3 + KASAN with a single ibv_post_send(IBV_WR_RDMA_WRITE) and
the wrap iova above; the kernel oopses in rxe_mr_copy+0x20d after
WARN at rxe_mr_iova_to_index+0x135.
Site A in rxe_resp.c (check_rkey()) reaches mr_check_range() with
attacker iova as well, so this patch also closes that path; Site B
(duplicate_request, also in rxe_resp.c) has an independent inline
check that wraps and is fixed in patch 3 of this series.
Fixes: 8700e3e7c485 ("Soft RoCE driver")
Cc: stable@vger.kernel.org # v4.8+
Reported-by: Tymbark7372 <tymbark7372@proton.me>
Signed-off-by: Tymbark7372 <tymbark7372@proton.me>
Assisted-by: Claude:claude-opus-4-7
---
drivers/infiniband/sw/rxe/rxe_mr.c | 12 +++++++++---
1 file changed, 9 insertions(+), 3 deletions(-)
diff --git a/drivers/infiniband/sw/rxe/rxe_mr.c b/drivers/infiniband/sw/rxe/rxe_mr.c
--- a/drivers/infiniband/sw/rxe/rxe_mr.c
+++ b/drivers/infiniband/sw/rxe/rxe_mr.c
@@ -30,13 +30,19 @@ int mr_check_range(struct rxe_mr *mr, u64 iova, size_t length)
return 0;
case IB_MR_TYPE_USER:
- case IB_MR_TYPE_MEM_REG:
- if (iova < mr->ibmr.iova ||
- iova + length > mr->ibmr.iova + mr->ibmr.length) {
+ case IB_MR_TYPE_MEM_REG: {
+ u64 iova_end, mr_end;
+
+ if (check_add_overflow(iova, length, &iova_end) ||
+ check_add_overflow(mr->ibmr.iova, mr->ibmr.length,
+ &mr_end) ||
+ iova < mr->ibmr.iova ||
+ iova_end > mr_end) {
rxe_dbg_mr(mr, "iova/length out of range\n");
return -EINVAL;
}
return 0;
+ }
default:
rxe_dbg_mr(mr, "mr type not supported\n");
--
2.43.0
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH 2/4] RDMA/rxe: Fix u64 iova+length overflow in rxe_check_pagefault
2026-05-21 19:44 [PATCH 0/4] RDMA/rxe: Fix u64 iova-overflow family in MR/ODP/RESP/MW paths Tymbark7372
2026-05-21 19:44 ` [PATCH 1/4] RDMA/rxe: Fix u64 iova+length overflow in mr_check_range Tymbark7372
@ 2026-05-21 19:44 ` Tymbark7372
2026-05-21 19:44 ` [PATCH 3/4] RDMA/rxe: Fix u64 iova+resid overflow in duplicate_request Tymbark7372
` (2 subsequent siblings)
4 siblings, 0 replies; 9+ messages in thread
From: Tymbark7372 @ 2026-05-21 19:44 UTC (permalink / raw)
To: linux-rdma; +Cc: zyjzyj2000, jgg, leonro, stable, Tymbark7372
rxe_check_pagefault() loops with the condition
"addr < iova + length" where iova is u64 and length is int. The
addition is promoted to u64 and wraps modulo 2^64 when iova is near
U64_MAX. With iova = 0xFFFFFFFFFFFFFC00 and length = 0x400 the sum
is 0; the loop body never executes; the function returns
need_fault = false; and the prefetch-fault check is bypassed.
Control then enters __rxe_odp_mr_copy(), which calls
rxe_odp_iova_to_index() on the wrap iova to obtain a huge index, and
dereferences umem_odp->map.pfn_list[huge_idx], an attacker-controlled
out-of-bounds slot. hmm_pfn_to_page() resolves the read value to an
attacker-chosen struct page, after which memcpy lands at
kmap_local_page(that_page) + offset, yielding arbitrary kernel write.
Reject any iova/length pair that overflows by computing iova_end with
check_add_overflow() once before the loop and using it as the loop
bound. A negative length is also rejected to avoid u64 promotion
masking the case.
Reproduced on v7.1.0-rc3 + KASAN with a single RDMA_WRITE against an
ODP-flagged MR; the kernel oopses in rxe_odp_mr_copy+0x205 with
RSI=0xfffffffffffffc00 (the wrap iova) and R13 holding the resolved
wrapped index. A working LPE chain that uses this OOB primitive to
overwrite cred_jar slab pages was demonstrated end-to-end on the same
verification kernel.
Fixes: 2fae67ab63db ("RDMA/rxe: Add support for Send/Recv/Write/Read with ODP")
Cc: stable@vger.kernel.org # v6.15+
Reported-by: Tymbark7372 <tymbark7372@proton.me>
Signed-off-by: Tymbark7372 <tymbark7372@proton.me>
Assisted-by: Claude:claude-opus-4-7
---
drivers/infiniband/sw/rxe/rxe_odp.c | 10 ++++++++--
1 file changed, 8 insertions(+), 2 deletions(-)
diff --git a/drivers/infiniband/sw/rxe/rxe_odp.c b/drivers/infiniband/sw/rxe/rxe_odp.c
--- a/drivers/infiniband/sw/rxe/rxe_odp.c
+++ b/drivers/infiniband/sw/rxe/rxe_odp.c
@@ -127,13 +127,19 @@ static inline bool rxe_check_pagefault(struct ib_umem_odp *umem_odp, u64 iova,
int length)
{
bool need_fault = false;
- u64 addr;
+ u64 addr, iova_end;
int idx;
+ if (length < 0 ||
+ check_add_overflow(iova, (u64)length, &iova_end)) {
+ /* let the pagefault path reject a bogus iova/length */
+ return true;
+ }
+
addr = iova & (~(BIT(umem_odp->page_shift) - 1));
/* Skim through all pages that are to be accessed. */
- while (addr < iova + length) {
+ while (addr < iova_end) {
idx = (addr - ib_umem_start(umem_odp)) >> umem_odp->page_shift;
if (!(umem_odp->map.pfn_list[idx] & HMM_PFN_VALID)) {
--
2.43.0
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH 3/4] RDMA/rxe: Fix u64 iova+resid overflow in duplicate_request
2026-05-21 19:44 [PATCH 0/4] RDMA/rxe: Fix u64 iova-overflow family in MR/ODP/RESP/MW paths Tymbark7372
2026-05-21 19:44 ` [PATCH 1/4] RDMA/rxe: Fix u64 iova+length overflow in mr_check_range Tymbark7372
2026-05-21 19:44 ` [PATCH 2/4] RDMA/rxe: Fix u64 iova+length overflow in rxe_check_pagefault Tymbark7372
@ 2026-05-21 19:44 ` Tymbark7372
2026-05-21 19:44 ` [PATCH 4/4] RDMA/rxe: Fix u64 addr+length overflow in rxe_check_bind_mw Tymbark7372
2026-05-22 2:54 ` [PATCH 0/4] RDMA/rxe: Fix u64 iova-overflow family in MR/ODP/RESP/MW paths Zhu Yanjun
4 siblings, 0 replies; 9+ messages in thread
From: Tymbark7372 @ 2026-05-21 19:44 UTC (permalink / raw)
To: linux-rdma; +Cc: zyjzyj2000, jgg, leonro, stable, Tymbark7372
In the duplicate-READ handling of duplicate_request(), the third
clause of the bound check computes (iova + resid) and compares it
with (res->read.va_org + res->read.length). iova is u64, resid is
u32 promoted to u64; the addition wraps modulo 2^64. An attacker
setting reth_va = 0xFFFFFFFFFFFFFC00 and reth_len = 0x400 causes the
left-hand sum to wrap to 0 while the right-hand sum stays small, so
the check passes and res->read.va is later set to the wrap address on
replay.
Downstream of either bound check site in rxe_resp.c, read_reply
calls rxe_mr_copy() with the wrap iova, which re-traverses
mr_check_range() and rxe_mr_iova_to_index(), and rxe_mr_copy_xarray()
OOB-derefs page_info[huge_idx]. The primitive is the same as patch
1 of this series, reached via the RDMA_READ path on a duplicate
(retransmitted) request.
Use check_add_overflow() on both sides of the comparison.
Reproduced on v7.1.0-rc3 + KASAN with a single
ibv_post_send(IBV_WR_RDMA_READ) followed by a retransmit of the
identical packet, with the wrap iova above. WARN at
rxe_mr_iova_to_index+0x135 followed by page-fault Oops in
rxe_mr_copy+0x20d on the READ path (rxe_receiver+0x3c70, distinct
from the WRITE offset rxe_receiver+0x6aa8 that the patch 1 trigger
reaches).
Fixes: 8700e3e7c485 ("Soft RoCE driver")
Cc: stable@vger.kernel.org # v4.8+
Reported-by: Tymbark7372 <tymbark7372@proton.me>
Signed-off-by: Tymbark7372 <tymbark7372@proton.me>
Assisted-by: Claude:claude-opus-4-7
---
drivers/infiniband/sw/rxe/rxe_resp.c | 11 ++++++++---
1 file changed, 8 insertions(+), 3 deletions(-)
diff --git a/drivers/infiniband/sw/rxe/rxe_resp.c b/drivers/infiniband/sw/rxe/rxe_resp.c
--- a/drivers/infiniband/sw/rxe/rxe_resp.c
+++ b/drivers/infiniband/sw/rxe/rxe_resp.c
@@ -1356,11 +1356,16 @@ static enum resp_states duplicate_request(struct rxe_qp *qp,
*/
u64 iova = reth_va(pkt);
u32 resid = reth_len(pkt);
+ u64 va_end_orig, va_end_new;
- if (iova < res->read.va_org ||
+ if (check_add_overflow(res->read.va_org,
+ (u64)res->read.length,
+ &va_end_orig) ||
+ check_add_overflow(iova, (u64)resid,
+ &va_end_new) ||
+ iova < res->read.va_org ||
resid > res->read.length ||
- (iova + resid) > (res->read.va_org +
- res->read.length)) {
+ va_end_new > va_end_orig) {
rc = RESPST_CLEANUP;
goto out;
}
--
2.43.0
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH 4/4] RDMA/rxe: Fix u64 addr+length overflow in rxe_check_bind_mw
2026-05-21 19:44 [PATCH 0/4] RDMA/rxe: Fix u64 iova-overflow family in MR/ODP/RESP/MW paths Tymbark7372
` (2 preceding siblings ...)
2026-05-21 19:44 ` [PATCH 3/4] RDMA/rxe: Fix u64 iova+resid overflow in duplicate_request Tymbark7372
@ 2026-05-21 19:44 ` Tymbark7372
2026-05-22 2:54 ` [PATCH 0/4] RDMA/rxe: Fix u64 iova-overflow family in MR/ODP/RESP/MW paths Zhu Yanjun
4 siblings, 0 replies; 9+ messages in thread
From: Tymbark7372 @ 2026-05-21 19:44 UTC (permalink / raw)
To: linux-rdma; +Cc: zyjzyj2000, jgg, leonro, stable, Tymbark7372
rxe_check_bind_mw() validates that a Type 2 memory window's range
[addr, addr + length) is contained within its parent MR's range
[mr->ibmr.iova, mr->ibmr.iova + mr->ibmr.length). Both end-addition
sums wrap modulo 2^64. An attacker can bind a memory window whose
nominal range exceeds the parent MR by wrapping the comparison sum
to a value below the parent's iova.
This is the same wrap class as patch 1 of this series; it was found
by sibling-site grep against the other rxe iova checks and is not on
the OOB-write path of the three primary bugs. I have not
demonstrated a downstream OOB primitive that uses this specific
escape, so it is filed here as a defensive sibling fix rather than as
a separate exploitable bug. Folding it into the same series keeps
the wrap-class fixes together.
Use check_add_overflow() on both ends.
Fixes: 8700e3e7c485 ("Soft RoCE driver")
Cc: stable@vger.kernel.org # v4.8+
Reported-by: Tymbark7372 <tymbark7372@proton.me>
Signed-off-by: Tymbark7372 <tymbark7372@proton.me>
Assisted-by: Claude:claude-opus-4-7
---
drivers/infiniband/sw/rxe/rxe_mw.c | 11 ++++++++---
1 file changed, 8 insertions(+), 3 deletions(-)
diff --git a/drivers/infiniband/sw/rxe/rxe_mw.c b/drivers/infiniband/sw/rxe/rxe_mw.c
--- a/drivers/infiniband/sw/rxe/rxe_mw.c
+++ b/drivers/infiniband/sw/rxe/rxe_mw.c
@@ -120,9 +120,14 @@
return -EINVAL;
}
} else {
- if (unlikely((wqe->wr.wr.mw.addr < mr->ibmr.iova) ||
- ((wqe->wr.wr.mw.addr + wqe->wr.wr.mw.length) >
- (mr->ibmr.iova + mr->ibmr.length)))) {
+ u64 mw_end, mr_end;
+
+ if (unlikely(check_add_overflow(wqe->wr.wr.mw.addr,
+ wqe->wr.wr.mw.length, &mw_end) ||
+ check_add_overflow(mr->ibmr.iova,
+ mr->ibmr.length, &mr_end) ||
+ wqe->wr.wr.mw.addr < mr->ibmr.iova ||
+ mw_end > mr_end)) {
rxe_dbg_mw(mw,
"attempt to bind a VA MW outside of the MR\n");
return -EINVAL;
--
2.43.0
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH 0/4] RDMA/rxe: Fix u64 iova-overflow family in MR/ODP/RESP/MW paths
2026-05-21 19:44 [PATCH 0/4] RDMA/rxe: Fix u64 iova-overflow family in MR/ODP/RESP/MW paths Tymbark7372
` (3 preceding siblings ...)
2026-05-21 19:44 ` [PATCH 4/4] RDMA/rxe: Fix u64 addr+length overflow in rxe_check_bind_mw Tymbark7372
@ 2026-05-22 2:54 ` Zhu Yanjun
2026-05-25 11:15 ` Tymbark7372
4 siblings, 1 reply; 9+ messages in thread
From: Zhu Yanjun @ 2026-05-22 2:54 UTC (permalink / raw)
To: Tymbark7372, linux-rdma, yanjun.zhu@linux.dev
Cc: zyjzyj2000, jgg, leonro, stable
在 2026/5/21 12:44, Tymbark7372 写道:
> This patchset fixes a family of u64 overflow bugs in the rxe Soft-RoCE
> driver. All four sites share one root cause: addition of an
> attacker-influenced iova/addr (u64) with an attacker-influenced
> length/resid (size_t/u32/int promoted to u64), without overflow
> check, leading to an OOB read/write primitive in the rxe responder
> workqueue.
The core premise of these commits is that a user-space program can
arbitrarily set the IOVA via /dev/infiniband/uverbs0. I am still
skeptical about this, as my understanding was that the IOVA is managed
by the subsystem and difficult for a user to modify. If it is indeed
possible for a user to control or change this IOVA, then I am completely
fine with this patchset.
Thanks a lot.
Zhu Yanjun
>
> I originally reported these to security@kernel.org. Jason Gunthorpe
> confirmed that rxe and siw are development-only drivers without
> embargo handling and asked me to send patches publicly, so I'm
> posting here per his direction. security@kernel.org is intentionally
> not in Cc per Jason's instruction.
>
> This is a resend of the patches I sent earlier today as attachments.
> Zhu Yanjun pointed out attachments aren't the convention and asked
> for inline format via git send-email.
>
> Patches:
>
> 1/4: rxe_mr.c mr_check_range
> The USER/MEM_REG case computes iova + length and compares to
> mr->ibmr.iova + mr->ibmr.length. Both additions wrap in u64.
> Use check_add_overflow() for both ends.
>
> 2/4: rxe_odp.c rxe_check_pagefault
> Loop condition addr < iova + length wraps when iova is near
> U64_MAX and length is positive. Compute iova_end with
> check_add_overflow() once and use it in the loop condition.
>
> 3/4: rxe_resp.c duplicate_request
> Third clause iova + resid > res->read.va_org + res->read.length
> has u64 wrap on both sides. Use check_add_overflow() for both
> ends. (Site A in check_rkey, also in rxe_resp.c, calls into
> mr_check_range and is closed by patch 1.)
>
> 4/4: rxe_mw.c rxe_check_bind_mw
> Same wrap class as patch 1. Found by sibling-site grep; not on
> the OOB-write path of the three primary bugs but a
> structurally-identical u64 wrap that would let an attacker bind
> a memory window outside its parent MR's range.
>
> Verification:
>
> Each of the three primary sibling triggers (patches 1, 2, 3) has been
> exercised on v7.1.0-rc3 + KASAN in QEMU as the OOB-write case.
> Patches 1 and 3 produce a single-page-fault Oops in rxe_mr_copy after
> the wrap. Patch 2 produces a single-page-fault Oops in
> rxe_odp_mr_copy. All three are triggered by a single ibv_post_send
> from an unprivileged local user with /dev/infiniband/uverbs0 open.
> A working LPE exploit demonstrated end-to-end privilege escalation
> via the rxe_odp path under the verification config (KASAN dev-build,
> selinux=0, nokaslr). Full PoC and writeup were attached to the
> original security@kernel.org submission.
>
> After applying all four patches, the same triggers no longer fire;
> the wrap checks correctly reject the attacker iova. Re-tested in the
> same QEMU+KASAN configuration.
>
> The trigger PoCs are simple libibverbs programs (one per sibling)
> that I am happy to provide on request.
>
> Fixes / stable:
>
> 1/4: Fixes 8700e3e7c485 ("Soft RoCE driver"), v4.8+
> 2/4: Fixes 2fae67ab63db ("RDMA/rxe: Add support for Send/Recv/Write/Read with ODP"), v6.15+
> 3/4: Fixes 8700e3e7c485 ("Soft RoCE driver"), v4.8+
> 4/4: Fixes 8700e3e7c485 ("Soft RoCE driver"), v4.8+
>
> Pre-f04d5b3d916c LTS branches carry the older wrap form
> iova > mr->ibmr.iova + mr->ibmr.length - length
> instead of the current `iova + length > ...` shape. Patches 1, 3, 4
> will need a backport variant for those branches; I can provide on
> request.
>
> Tymbark7372 (4):
> RDMA/rxe: Fix u64 iova+length overflow in mr_check_range
> RDMA/rxe: Fix u64 iova+length overflow in rxe_check_pagefault
> RDMA/rxe: Fix u64 iova+resid overflow in duplicate_request
> RDMA/rxe: Fix u64 addr+length overflow in rxe_check_bind_mw
>
> drivers/infiniband/sw/rxe/rxe_mr.c | 12 +++++++++---
> drivers/infiniband/sw/rxe/rxe_odp.c | 10 ++++++++--
> drivers/infiniband/sw/rxe/rxe_resp.c | 11 ++++++++---
> drivers/infiniband/sw/rxe/rxe_mw.c | 11 ++++++++---
> 4 files changed, 33 insertions(+), 11 deletions(-)
>
> --
> 2.43.0
>
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH 1/4] RDMA/rxe: Fix u64 iova+length overflow in mr_check_range
2026-05-21 19:44 ` [PATCH 1/4] RDMA/rxe: Fix u64 iova+length overflow in mr_check_range Tymbark7372
@ 2026-05-22 4:44 ` Greg KH
0 siblings, 0 replies; 9+ messages in thread
From: Greg KH @ 2026-05-22 4:44 UTC (permalink / raw)
To: Tymbark7372; +Cc: linux-rdma, zyjzyj2000, jgg, leonro, stable
On Thu, May 21, 2026 at 07:44:08PM +0000, Tymbark7372 wrote:
> In mr_check_range(), the IB_MR_TYPE_USER and IB_MR_TYPE_MEM_REG case
> computes both iova + length and mr->ibmr.iova + mr->ibmr.length without
> overflow check. Both iova (u64) and length (size_t) are 64-bit on
> 64-bit platforms. An attacker setting iova = 0xFFFFFFFFFFFFFC00 and
> length = 0x400 wraps the sum to 0, so the bound check
> "iova + length > mr->ibmr.iova + mr->ibmr.length" passes.
>
> After the bypass, rxe_mr_iova_to_index() computes a huge index value;
> WARN_ON(idx >= mr->nbuf) fires but does not abort, and
> rxe_mr_copy_xarray() then dereferences page_info[huge_idx], an
> attacker-controlled out-of-bounds slot. In the RXE_TO_MR_OBJ
> direction this becomes an OOB write of attacker payload bytes through
> info->page + info->offset.
>
> Use check_add_overflow() on both ends to reject any iova/length pair
> that wraps. Also explicitly scope the local declarations introduced
> by the helper variables.
>
> Reachable from any unprivileged local process with
> /dev/infiniband/uverbs0 open (world-rw on distros that ship the
> rdma-core udev rules) and from an unauthenticated remote peer over
> UDP/4791 (RoCEv2) when the target rkey/QPN are known. Reproduced on
> v7.1.0-rc3 + KASAN with a single ibv_post_send(IBV_WR_RDMA_WRITE) and
> the wrap iova above; the kernel oopses in rxe_mr_copy+0x20d after
> WARN at rxe_mr_iova_to_index+0x135.
>
> Site A in rxe_resp.c (check_rkey()) reaches mr_check_range() with
> attacker iova as well, so this patch also closes that path; Site B
> (duplicate_request, also in rxe_resp.c) has an independent inline
> check that wraps and is fixed in patch 3 of this series.
>
> Fixes: 8700e3e7c485 ("Soft RoCE driver")
> Cc: stable@vger.kernel.org # v4.8+
> Reported-by: Tymbark7372 <tymbark7372@proton.me>
> Signed-off-by: Tymbark7372 <tymbark7372@proton.me>
We need a real name for the From: and signed-off-by line, and no need
for the duplicate reported-by line.
thanks,
greg k-h
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH 0/4] RDMA/rxe: Fix u64 iova-overflow family in MR/ODP/RESP/MW paths
2026-05-22 2:54 ` [PATCH 0/4] RDMA/rxe: Fix u64 iova-overflow family in MR/ODP/RESP/MW paths Zhu Yanjun
@ 2026-05-25 11:15 ` Tymbark7372
2026-05-25 20:54 ` Zhu Yanjun
0 siblings, 1 reply; 9+ messages in thread
From: Tymbark7372 @ 2026-05-25 11:15 UTC (permalink / raw)
To: Zhu Yanjun; +Cc: linux-rdma, zyjzyj2000, jgg, leonro, stable
Hi Zhu,
Thanks for the reply. The iova on USER MRs is fully attacker-controlled
at three entry points; cited file:line so it's verifiable:
1. Registration via /dev/infiniband/uverbs0:
drivers/infiniband/core/uverbs_cmd.c:746 does
`mr->iova = cmd.hca_va`. `cmd.hca_va` comes straight from the
user's `struct ib_uverbs_reg_mr` over the UAPI. The only check
(line 714) is that the low PAGE_SHIFT bits of cmd.hca_va match
cmd.start -- high bits are not constrained. Line 731 passes
`cmd.hca_va` as the `iova` argument to
`pd->device->ops.reg_user_mr()`, which in rxe is
`rxe_reg_user_mr()`. No subsystem rewriting on this path.
2. Work-request posting via ibv_post_send():
drivers/infiniband/sw/rxe/rxe_verbs.c:822 copies the user's
`ibwr->sg_list` directly into the WQE; `sge->addr` is the iova
that subsequently flows to `mr_check_range()` on SEND/RDMA-WRITE.
User chooses any u64.
3. Network path (RoCEv2):
drivers/infiniband/sw/rxe/rxe_resp.c:409 reads
`qp->resp.va = reth_va(pkt)` directly from the RETH wire header
on inbound RDMA-WRITE/READ/ATOMIC. Line 1357 does the same in
duplicate_request. A peer on UDP/4791 with a known QPN/rkey
controls iova directly.
PoC is a small libibverbs program: register a destination MR with
hca_va = 0xFFFFFFFFFFFFFC00, then post a single ibv_post_send()
with IBV_WR_RDMA_WRITE pointing at that MR's rkey, sge.length = 0x400.
On v7.1.0-rc3 + KASAN this hits:
WARNING ... at rxe_mr_iova_to_index+0x135/0x180
...
BUG: unable to handle page fault for address: ffff887b3ba27250
RIP: 0010:rxe_mr_copy+0x20d/0x5e0
Reproduced as unprivileged uid with /dev/infiniband/uverbs0 open.
Happy to send the four PoC sources (one per sibling) inline if you'd
like to reproduce.
Tymbark7372
On Friday, May 22nd, 2026 at 4:54 AM, Zhu Yanjun <yanjun.zhu@linux.dev> wrote:
> 在 2026/5/21 12:44, Tymbark7372 写道:
> > This patchset fixes a family of u64 overflow bugs in the rxe Soft-RoCE
> > driver. All four sites share one root cause: addition of an
> > attacker-influenced iova/addr (u64) with an attacker-influenced
> > length/resid (size_t/u32/int promoted to u64), without overflow
> > check, leading to an OOB read/write primitive in the rxe responder
> > workqueue.
>
> The core premise of these commits is that a user-space program can
> arbitrarily set the IOVA via /dev/infiniband/uverbs0. I am still
> skeptical about this, as my understanding was that the IOVA is managed
> by the subsystem and difficult for a user to modify. If it is indeed
> possible for a user to control or change this IOVA, then I am completely
> fine with this patchset.
>
> Thanks a lot.
> Zhu Yanjun
>
> >
> > I originally reported these to security@kernel.org. Jason Gunthorpe
> > confirmed that rxe and siw are development-only drivers without
> > embargo handling and asked me to send patches publicly, so I'm
> > posting here per his direction. security@kernel.org is intentionally
> > not in Cc per Jason's instruction.
> >
> > This is a resend of the patches I sent earlier today as attachments.
> > Zhu Yanjun pointed out attachments aren't the convention and asked
> > for inline format via git send-email.
> >
> > Patches:
> >
> > 1/4: rxe_mr.c mr_check_range
> > The USER/MEM_REG case computes iova + length and compares to
> > mr->ibmr.iova + mr->ibmr.length. Both additions wrap in u64.
> > Use check_add_overflow() for both ends.
> >
> > 2/4: rxe_odp.c rxe_check_pagefault
> > Loop condition addr < iova + length wraps when iova is near
> > U64_MAX and length is positive. Compute iova_end with
> > check_add_overflow() once and use it in the loop condition.
> >
> > 3/4: rxe_resp.c duplicate_request
> > Third clause iova + resid > res->read.va_org + res->read.length
> > has u64 wrap on both sides. Use check_add_overflow() for both
> > ends. (Site A in check_rkey, also in rxe_resp.c, calls into
> > mr_check_range and is closed by patch 1.)
> >
> > 4/4: rxe_mw.c rxe_check_bind_mw
> > Same wrap class as patch 1. Found by sibling-site grep; not on
> > the OOB-write path of the three primary bugs but a
> > structurally-identical u64 wrap that would let an attacker bind
> > a memory window outside its parent MR's range.
> >
> > Verification:
> >
> > Each of the three primary sibling triggers (patches 1, 2, 3) has been
> > exercised on v7.1.0-rc3 + KASAN in QEMU as the OOB-write case.
> > Patches 1 and 3 produce a single-page-fault Oops in rxe_mr_copy after
> > the wrap. Patch 2 produces a single-page-fault Oops in
> > rxe_odp_mr_copy. All three are triggered by a single ibv_post_send
> > from an unprivileged local user with /dev/infiniband/uverbs0 open.
> > A working LPE exploit demonstrated end-to-end privilege escalation
> > via the rxe_odp path under the verification config (KASAN dev-build,
> > selinux=0, nokaslr). Full PoC and writeup were attached to the
> > original security@kernel.org submission.
> >
> > After applying all four patches, the same triggers no longer fire;
> > the wrap checks correctly reject the attacker iova. Re-tested in the
> > same QEMU+KASAN configuration.
> >
> > The trigger PoCs are simple libibverbs programs (one per sibling)
> > that I am happy to provide on request.
> >
> > Fixes / stable:
> >
> > 1/4: Fixes 8700e3e7c485 ("Soft RoCE driver"), v4.8+
> > 2/4: Fixes 2fae67ab63db ("RDMA/rxe: Add support for Send/Recv/Write/Read with ODP"), v6.15+
> > 3/4: Fixes 8700e3e7c485 ("Soft RoCE driver"), v4.8+
> > 4/4: Fixes 8700e3e7c485 ("Soft RoCE driver"), v4.8+
> >
> > Pre-f04d5b3d916c LTS branches carry the older wrap form
> > iova > mr->ibmr.iova + mr->ibmr.length - length
> > instead of the current `iova + length > ...` shape. Patches 1, 3, 4
> > will need a backport variant for those branches; I can provide on
> > request.
> >
> > Tymbark7372 (4):
> > RDMA/rxe: Fix u64 iova+length overflow in mr_check_range
> > RDMA/rxe: Fix u64 iova+length overflow in rxe_check_pagefault
> > RDMA/rxe: Fix u64 iova+resid overflow in duplicate_request
> > RDMA/rxe: Fix u64 addr+length overflow in rxe_check_bind_mw
> >
> > drivers/infiniband/sw/rxe/rxe_mr.c | 12 +++++++++---
> > drivers/infiniband/sw/rxe/rxe_odp.c | 10 ++++++++--
> > drivers/infiniband/sw/rxe/rxe_resp.c | 11 ++++++++---
> > drivers/infiniband/sw/rxe/rxe_mw.c | 11 ++++++++---
> > 4 files changed, 33 insertions(+), 11 deletions(-)
> >
> > --
> > 2.43.0
> >
>
>
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH 0/4] RDMA/rxe: Fix u64 iova-overflow family in MR/ODP/RESP/MW paths
2026-05-25 11:15 ` Tymbark7372
@ 2026-05-25 20:54 ` Zhu Yanjun
0 siblings, 0 replies; 9+ messages in thread
From: Zhu Yanjun @ 2026-05-25 20:54 UTC (permalink / raw)
To: Tymbark7372, yanjun.zhu@linux.dev
Cc: linux-rdma, zyjzyj2000, jgg, leonro, stable
在 2026/5/25 4:15, Tymbark7372 写道:
> Hi Zhu,
>
> Thanks for the reply. The iova on USER MRs is fully attacker-controlled
> at three entry points; cited file:line so it's verifiable:
>
> 1. Registration via /dev/infiniband/uverbs0:
> drivers/infiniband/core/uverbs_cmd.c:746 does
> `mr->iova = cmd.hca_va`. `cmd.hca_va` comes straight from the
> user's `struct ib_uverbs_reg_mr` over the UAPI. The only check
> (line 714) is that the low PAGE_SHIFT bits of cmd.hca_va match
> cmd.start -- high bits are not constrained. Line 731 passes
> `cmd.hca_va` as the `iova` argument to
> `pd->device->ops.reg_user_mr()`, which in rxe is
> `rxe_reg_user_mr()`. No subsystem rewriting on this path.
>
> 2. Work-request posting via ibv_post_send():
> drivers/infiniband/sw/rxe/rxe_verbs.c:822 copies the user's
> `ibwr->sg_list` directly into the WQE; `sge->addr` is the iova
> that subsequently flows to `mr_check_range()` on SEND/RDMA-WRITE.
> User chooses any u64.
>
> 3. Network path (RoCEv2):
> drivers/infiniband/sw/rxe/rxe_resp.c:409 reads
> `qp->resp.va = reth_va(pkt)` directly from the RETH wire header
> on inbound RDMA-WRITE/READ/ATOMIC. Line 1357 does the same in
> duplicate_request. A peer on UDP/4791 with a known QPN/rkey
> controls iova directly.
>
> PoC is a small libibverbs program: register a destination MR with
> hca_va = 0xFFFFFFFFFFFFFC00, then post a single ibv_post_send()
> with IBV_WR_RDMA_WRITE pointing at that MR's rkey, sge.length = 0x400.
> On v7.1.0-rc3 + KASAN this hits:
>
> WARNING ... at rxe_mr_iova_to_index+0x135/0x180
> ...
> BUG: unable to handle page fault for address: ffff887b3ba27250
> RIP: 0010:rxe_mr_copy+0x20d/0x5e0
>
> Reproduced as unprivileged uid with /dev/infiniband/uverbs0 open.
> Happy to send the four PoC sources (one per sibling) inline if you'd
> like to reproduce.
Thank you very much. If you could share a PoC source, I would really
appreciate it, as it would help us reproduce the issue locally.
If sharing the PoC is not convenient, it would also be very helpful if
you could post your reproduction evidence or logs publicly on the
community thread, so others can independently verify and confirm
the issue as well.
Thanks a lot.
Zhu Yanjun
>
> Tymbark7372
>
>
>
> On Friday, May 22nd, 2026 at 4:54 AM, Zhu Yanjun <yanjun.zhu@linux.dev> wrote:
>
>> 在 2026/5/21 12:44, Tymbark7372 写道:
>>> This patchset fixes a family of u64 overflow bugs in the rxe Soft-RoCE
>>> driver. All four sites share one root cause: addition of an
>>> attacker-influenced iova/addr (u64) with an attacker-influenced
>>> length/resid (size_t/u32/int promoted to u64), without overflow
>>> check, leading to an OOB read/write primitive in the rxe responder
>>> workqueue.
>> The core premise of these commits is that a user-space program can
>> arbitrarily set the IOVA via /dev/infiniband/uverbs0. I am still
>> skeptical about this, as my understanding was that the IOVA is managed
>> by the subsystem and difficult for a user to modify. If it is indeed
>> possible for a user to control or change this IOVA, then I am completely
>> fine with this patchset.
>>
>> Thanks a lot.
>> Zhu Yanjun
>>
>>> I originally reported these to security@kernel.org. Jason Gunthorpe
>>> confirmed that rxe and siw are development-only drivers without
>>> embargo handling and asked me to send patches publicly, so I'm
>>> posting here per his direction. security@kernel.org is intentionally
>>> not in Cc per Jason's instruction.
>>>
>>> This is a resend of the patches I sent earlier today as attachments.
>>> Zhu Yanjun pointed out attachments aren't the convention and asked
>>> for inline format via git send-email.
>>>
>>> Patches:
>>>
>>> 1/4: rxe_mr.c mr_check_range
>>> The USER/MEM_REG case computes iova + length and compares to
>>> mr->ibmr.iova + mr->ibmr.length. Both additions wrap in u64.
>>> Use check_add_overflow() for both ends.
>>>
>>> 2/4: rxe_odp.c rxe_check_pagefault
>>> Loop condition addr < iova + length wraps when iova is near
>>> U64_MAX and length is positive. Compute iova_end with
>>> check_add_overflow() once and use it in the loop condition.
>>>
>>> 3/4: rxe_resp.c duplicate_request
>>> Third clause iova + resid > res->read.va_org + res->read.length
>>> has u64 wrap on both sides. Use check_add_overflow() for both
>>> ends. (Site A in check_rkey, also in rxe_resp.c, calls into
>>> mr_check_range and is closed by patch 1.)
>>>
>>> 4/4: rxe_mw.c rxe_check_bind_mw
>>> Same wrap class as patch 1. Found by sibling-site grep; not on
>>> the OOB-write path of the three primary bugs but a
>>> structurally-identical u64 wrap that would let an attacker bind
>>> a memory window outside its parent MR's range.
>>>
>>> Verification:
>>>
>>> Each of the three primary sibling triggers (patches 1, 2, 3) has been
>>> exercised on v7.1.0-rc3 + KASAN in QEMU as the OOB-write case.
>>> Patches 1 and 3 produce a single-page-fault Oops in rxe_mr_copy after
>>> the wrap. Patch 2 produces a single-page-fault Oops in
>>> rxe_odp_mr_copy. All three are triggered by a single ibv_post_send
>>> from an unprivileged local user with /dev/infiniband/uverbs0 open.
>>> A working LPE exploit demonstrated end-to-end privilege escalation
>>> via the rxe_odp path under the verification config (KASAN dev-build,
>>> selinux=0, nokaslr). Full PoC and writeup were attached to the
>>> original security@kernel.org submission.
>>>
>>> After applying all four patches, the same triggers no longer fire;
>>> the wrap checks correctly reject the attacker iova. Re-tested in the
>>> same QEMU+KASAN configuration.
>>>
>>> The trigger PoCs are simple libibverbs programs (one per sibling)
>>> that I am happy to provide on request.
>>>
>>> Fixes / stable:
>>>
>>> 1/4: Fixes 8700e3e7c485 ("Soft RoCE driver"), v4.8+
>>> 2/4: Fixes 2fae67ab63db ("RDMA/rxe: Add support for Send/Recv/Write/Read with ODP"), v6.15+
>>> 3/4: Fixes 8700e3e7c485 ("Soft RoCE driver"), v4.8+
>>> 4/4: Fixes 8700e3e7c485 ("Soft RoCE driver"), v4.8+
>>>
>>> Pre-f04d5b3d916c LTS branches carry the older wrap form
>>> iova > mr->ibmr.iova + mr->ibmr.length - length
>>> instead of the current `iova + length > ...` shape. Patches 1, 3, 4
>>> will need a backport variant for those branches; I can provide on
>>> request.
>>>
>>> Tymbark7372 (4):
>>> RDMA/rxe: Fix u64 iova+length overflow in mr_check_range
>>> RDMA/rxe: Fix u64 iova+length overflow in rxe_check_pagefault
>>> RDMA/rxe: Fix u64 iova+resid overflow in duplicate_request
>>> RDMA/rxe: Fix u64 addr+length overflow in rxe_check_bind_mw
>>>
>>> drivers/infiniband/sw/rxe/rxe_mr.c | 12 +++++++++---
>>> drivers/infiniband/sw/rxe/rxe_odp.c | 10 ++++++++--
>>> drivers/infiniband/sw/rxe/rxe_resp.c | 11 ++++++++---
>>> drivers/infiniband/sw/rxe/rxe_mw.c | 11 ++++++++---
>>> 4 files changed, 33 insertions(+), 11 deletions(-)
>>>
>>> --
>>> 2.43.0
>>>
>>
--
Best Regards,
Yanjun.Zhu
^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2026-05-25 20:54 UTC | newest]
Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-05-21 19:44 [PATCH 0/4] RDMA/rxe: Fix u64 iova-overflow family in MR/ODP/RESP/MW paths Tymbark7372
2026-05-21 19:44 ` [PATCH 1/4] RDMA/rxe: Fix u64 iova+length overflow in mr_check_range Tymbark7372
2026-05-22 4:44 ` Greg KH
2026-05-21 19:44 ` [PATCH 2/4] RDMA/rxe: Fix u64 iova+length overflow in rxe_check_pagefault Tymbark7372
2026-05-21 19:44 ` [PATCH 3/4] RDMA/rxe: Fix u64 iova+resid overflow in duplicate_request Tymbark7372
2026-05-21 19:44 ` [PATCH 4/4] RDMA/rxe: Fix u64 addr+length overflow in rxe_check_bind_mw Tymbark7372
2026-05-22 2:54 ` [PATCH 0/4] RDMA/rxe: Fix u64 iova-overflow family in MR/ODP/RESP/MW paths Zhu Yanjun
2026-05-25 11:15 ` Tymbark7372
2026-05-25 20:54 ` Zhu Yanjun
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox