RDMA/rxe: Validate num_sge/cur_sge before indexing wqe->dma.sge[]

For a user QP, qp->sq.queue is a ring the application writes directly,
so rxe_post_send() takes the is_user branch and only schedules send_task
without validating the WQE. rxe_requester() consumes it in place via
req_next_wqe() and calls copy_data(), which indexes
&wqe->dma.sge[cur_sge] with the attacker-controlled num_sge/cur_sge.
Only the kernel path bounds num_sge (validate_send_wr()); the user WQE
is never checked, so a local unprivileged user can post a WQE with an
out-of-range cur_sge or oversized num_sge and force an out-of-bounds
read of the per-WQE sge array in copy_data() (vmalloc OOB read, local
DoS).

Bound num_sge to qp->sq.max_sge in rxe_requester() before use, the way
get_srq_wqe() already guards SRQ entries, and bound cur_sge only when
the WQE carries payload (dma.resid): copy_data() returns early on a
zero-length copy before touching dma->sge[], so a zero-payload WQE --
the only kind a max_sge == 0 QP can post -- stays valid.

Reproduced under KASAN; the vmalloc-out-of-bounds in copy_data() is gone.

Fixes: 8700e3e7c4 ("Soft RoCE driver")
Reviewed-by: Zhu Yanjun <yanjun.zhu@linux.dev>
Signed-off-by: Ibrahim Hashimov <security@auditcode.ai>
Link: https://patch.msgid.link/20260712122149.78142-1-security@auditcode.ai
Assisted-by: AuditCode-AI:2026.07
Signed-off-by: Leon Romanovsky <leon@kernel.org>
This commit is contained in:
Ibrahim Hashimov 2026-07-12 14:21:49 +02:00 committed by Leon Romanovsky
parent 6f70142374
commit 126c757e4c

View File

@ -701,6 +701,21 @@ int rxe_requester(struct rxe_qp *qp)
if (unlikely(!wqe))
goto exit;
/*
* Don't trust user space data: a user QP's WQE comes from an mmap'd
* ring, so num_sge/cur_sge are attacker-controlled. Bound num_sge like
* get_srq_wqe(); bound cur_sge only when payload exists (dma.resid),
* since copy_data() skips dma->sge[] on a zero-length copy (all a
* max_sge == 0 QP can post).
*/
if (unlikely(wqe->dma.num_sge > qp->sq.max_sge ||
(wqe->dma.resid &&
wqe->dma.cur_sge >= qp->sq.max_sge))) {
rxe_dbg_qp(qp, "invalid num_sge/cur_sge in send wqe\n");
wqe->status = IB_WC_LOC_QP_OP_ERR;
goto err;
}
if (rxe_wqe_is_fenced(qp, wqe)) {
qp->req.wait_fence = 1;
goto exit;