* [PATCH v3] RDMA/rxe: Validate inline data range in user WQEs
@ 2026-10-04 6:44 Jiale Yao
2026-10-05 0:29 ` Zhu Yanjun
0 siblings, 1 reply; 2+ messages in thread
From: Jiale Yao @ 2026-10-04 6:44 UTC (permalink / raw)
To: Zhu Yanjun, Jason Gunthorpe, Leon Romanovsky, Doug Ledford,
Moni Shoua, Haggai Eran, Kamal Heib, Amir Vadai, linux-rdma,
linux-kernel
Cc: Jiale Yao
For a user QP, the send queue is an mmap'd ring which userspace writes
directly. rxe_post_send() only schedules the send task for such a QP,
so userspace can also change WQE fields while rxe_requester() processes
the WQE.
Commit 126c757e4cd46f866ddc283143b58eb4d9bf52cd ("RDMA/rxe:
Validate num_sge/cur_sge before indexing wqe->dma.sge[]") added bounds
checks for two members of the userspace-controlled dma structure, but
left sge_offset unchecked. For an inline WQE, finish_packet() uses that
value directly as an index into inline_data[] and copies dma.resid bytes
from the resulting pointer into the packet payload.
A local user with access to uverbs can therefore put an out-of-range
sge_offset in the mmap'd SQ ring. This can disclose kernel memory in the
outgoing packet or cause a vmalloc out-of-bounds access.
Since sge_offset comes from shared memory, validating it in
rxe_requester() and then reading it again in finish_packet() leaves a
TOCTOU window. Load it exactly once with READ_ONCE() in finish_packet(),
validate that local value, and use the same value for the copy and update.
Check the offset first and use subtraction for the length check to avoid
an integer overflow.
I reproduced this on Linux 7.3-rc4 with an RC user QP, IB_SEND_INLINE,
a 64-byte residual length, and sge_offset set to 0x100000. KASAN
reported:
BUG: KASAN: vmalloc-out-of-bounds in rxe_requester+0x1f27/0x4940
Read of size 64 at addr ffffc90000191250 by task kworker/u16:0/12
Workqueue: rxe_wq do_work
Call Trace:
__asan_memcpy
rxe_requester+0x1f27/0x4940
rxe_sender+0xe/0x30
do_work+0x184/0x3d0
process_scheduled_works+0x7c0/0xf10
Fixes: 8700e3e7c485 ("Soft RoCE driver")
Link: https://lore.kernel.org/all/20260708224534.1206-1-security@auditcode.ai/
Signed-off-by: Jiale Yao <yaojiale02@163.com>
---
Notes:
Changes in v3:
- Read sge_offset from the shared WQE with READ_ONCE(), as requested.
Changes in v2:
- Copy sge_offset into a local variable in finish_packet(), validate that
value, and reuse it for the memcpy and update.
drivers/infiniband/sw/rxe/rxe_req.c | 14 +++++++++++---
1 file changed, 11 insertions(+), 3 deletions(-)
diff --git a/drivers/infiniband/sw/rxe/rxe_req.c b/drivers/infiniband/sw/rxe/rxe_req.c
index 24f5c044363f..9be753d2e5dd 100644
--- a/drivers/infiniband/sw/rxe/rxe_req.c
+++ b/drivers/infiniband/sw/rxe/rxe_req.c
@@ -503,6 +503,7 @@ static int finish_packet(struct rxe_qp *qp, struct rxe_av *av,
struct sk_buff *skb, u32 payload)
{
int err;
+ u32 sge_offset;
err = rxe_prepare(av, pkt, skb);
if (err)
@@ -510,12 +511,19 @@ static int finish_packet(struct rxe_qp *qp, struct rxe_av *av,
if (pkt->mask & RXE_WRITE_OR_SEND_MASK) {
if (wqe->wr.send_flags & IB_SEND_INLINE) {
- u8 *tmp = &wqe->dma.inline_data[wqe->dma.sge_offset];
+ sge_offset = READ_ONCE(wqe->dma.sge_offset);
+ if (unlikely(sge_offset > qp->sq.max_inline ||
+ payload >
+ qp->sq.max_inline - sge_offset)) {
+ rxe_dbg_qp(qp, "invalid inline data range in send wqe\n");
+ return -EINVAL;
+ }
- memcpy(payload_addr(pkt), tmp, payload);
+ memcpy(payload_addr(pkt),
+ &wqe->dma.inline_data[sge_offset], payload);
wqe->dma.resid -= payload;
- wqe->dma.sge_offset += payload;
+ wqe->dma.sge_offset = sge_offset + payload;
} else {
err = copy_data(qp->pd, 0, &wqe->dma,
payload_addr(pkt), payload,
--
2.34.1
^ permalink raw reply [flat|nested] 2+ messages in thread* Re: [PATCH v3] RDMA/rxe: Validate inline data range in user WQEs
2026-10-04 6:44 [PATCH v3] RDMA/rxe: Validate inline data range in user WQEs Jiale Yao
@ 2026-10-05 0:29 ` Zhu Yanjun
0 siblings, 0 replies; 2+ messages in thread
From: Zhu Yanjun @ 2026-10-05 0:29 UTC (permalink / raw)
To: Jiale Yao, Zhu Yanjun, Jason Gunthorpe, Leon Romanovsky,
Doug Ledford, Moni Shoua, Haggai Eran, Kamal Heib, Amir Vadai,
linux-rdma, linux-kernel, yanjun.zhu
在 2026/10/3 23:44, Jiale Yao 写道:
> For a user QP, the send queue is an mmap'd ring which userspace writes
> directly. rxe_post_send() only schedules the send task for such a QP,
> so userspace can also change WQE fields while rxe_requester() processes
> the WQE.
>
> Commit 126c757e4cd46f866ddc283143b58eb4d9bf52cd ("RDMA/rxe:
> Validate num_sge/cur_sge before indexing wqe->dma.sge[]") added bounds
> checks for two members of the userspace-controlled dma structure, but
> left sge_offset unchecked. For an inline WQE, finish_packet() uses that
> value directly as an index into inline_data[] and copies dma.resid bytes
> from the resulting pointer into the packet payload.
>
> A local user with access to uverbs can therefore put an out-of-range
> sge_offset in the mmap'd SQ ring. This can disclose kernel memory in the
> outgoing packet or cause a vmalloc out-of-bounds access.
>
> Since sge_offset comes from shared memory, validating it in
> rxe_requester() and then reading it again in finish_packet() leaves a
> TOCTOU window. Load it exactly once with READ_ONCE() in finish_packet(),
> validate that local value, and use the same value for the copy and update.
> Check the offset first and use subtraction for the length check to avoid
> an integer overflow.
>
> I reproduced this on Linux 7.3-rc4 with an RC user QP, IB_SEND_INLINE,
> a 64-byte residual length, and sge_offset set to 0x100000. KASAN
> reported:
>
> BUG: KASAN: vmalloc-out-of-bounds in rxe_requester+0x1f27/0x4940
> Read of size 64 at addr ffffc90000191250 by task kworker/u16:0/12
> Workqueue: rxe_wq do_work
> Call Trace:
> __asan_memcpy
> rxe_requester+0x1f27/0x4940
> rxe_sender+0xe/0x30
> do_work+0x184/0x3d0
> process_scheduled_works+0x7c0/0xf10
Conceptually, wqe->dma.sge_offset is runtime state that should be
exclusively managed by the kernel, but mapping the SQ into user space
via mmap exposes it to untrusted asynchronous writes.
Beyond finish_packet(), every reader of sge_offset across the driver
(such as in rxe_sge.c and rxe_resp.c) must treat it as untrusted input.
We should audit all access points to ensure they consistently use a
READ_ONCE() local snapshot followed by underflow-safe bounds checks.
Longer term, moving kernel-managed progress state into kernel-private
memory would eliminate this attack surface entirely.
Yanjun Zhu
>
> Fixes: 8700e3e7c485 ("Soft RoCE driver")
> Link: https://lore.kernel.org/all/20260708224534.1206-1-security@auditcode.ai/
> Signed-off-by: Jiale Yao <yaojiale02@163.com>
> ---
>
> Notes:
> Changes in v3:
> - Read sge_offset from the shared WQE with READ_ONCE(), as requested.
>
> Changes in v2:
> - Copy sge_offset into a local variable in finish_packet(), validate that
> value, and reuse it for the memcpy and update.
>
> drivers/infiniband/sw/rxe/rxe_req.c | 14 +++++++++++---
> 1 file changed, 11 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/infiniband/sw/rxe/rxe_req.c b/drivers/infiniband/sw/rxe/rxe_req.c
> index 24f5c044363f..9be753d2e5dd 100644
> --- a/drivers/infiniband/sw/rxe/rxe_req.c
> +++ b/drivers/infiniband/sw/rxe/rxe_req.c
> @@ -503,6 +503,7 @@ static int finish_packet(struct rxe_qp *qp, struct rxe_av *av,
> struct sk_buff *skb, u32 payload)
> {
> int err;
> + u32 sge_offset;
>
> err = rxe_prepare(av, pkt, skb);
> if (err)
> @@ -510,12 +511,19 @@ static int finish_packet(struct rxe_qp *qp, struct rxe_av *av,
>
> if (pkt->mask & RXE_WRITE_OR_SEND_MASK) {
> if (wqe->wr.send_flags & IB_SEND_INLINE) {
> - u8 *tmp = &wqe->dma.inline_data[wqe->dma.sge_offset];
> + sge_offset = READ_ONCE(wqe->dma.sge_offset);
> + if (unlikely(sge_offset > qp->sq.max_inline ||
> + payload >
> + qp->sq.max_inline - sge_offset)) {
> + rxe_dbg_qp(qp, "invalid inline data range in send wqe\n");
> + return -EINVAL;
> + }
>
> - memcpy(payload_addr(pkt), tmp, payload);
> + memcpy(payload_addr(pkt),
> + &wqe->dma.inline_data[sge_offset], payload);
>
> wqe->dma.resid -= payload;
> - wqe->dma.sge_offset += payload;
> + wqe->dma.sge_offset = sge_offset + payload;
> } else {
> err = copy_data(qp->pd, 0, &wqe->dma,
> payload_addr(pkt), payload,
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2026-10-05 0:29 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-10-04 6:44 [PATCH v3] RDMA/rxe: Validate inline data range in user WQEs Jiale Yao
2026-10-05 0:29 ` Zhu Yanjun
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®