]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
RDMA/rxe: Fix TOCTOU heap overflow in get_srq_wqe
authorTristan Madani <tristmd@gmail.com>
Mon, 18 May 2026 21:50:39 +0000 (21:50 +0000)
committerJason Gunthorpe <jgg@nvidia.com>
Fri, 29 May 2026 23:32:48 +0000 (20:32 -0300)
get_srq_wqe() reads wqe->dma.num_sge from the shared receive queue
buffer, which is mapped into userspace. It validates num_sge against
max_sge, but then re-reads the same field to calculate the memcpy
size. A concurrent userspace thread can modify num_sge between
validation and use, causing a heap buffer overflow when copying the
WQE into qp->resp.srq_wqe.

Read num_sge into a local variable and use it for both the bounds
check and the size calculation.

Fixes: 8700e3e7c485 ("Soft RoCE driver")
Link: https://patch.msgid.link/r/20260518215040.1598586-2-tristan@talencesecurity.com
Signed-off-by: Tristan Madani <tristan@talencesecurity.com>
Reviewed-by: Zhu Yanjun <yanjun.zhu@linux.dev>
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
drivers/infiniband/sw/rxe/rxe_resp.c

index d8d1b7f2f3416e3e41b04dc1927a9081ac53a35d..29438bcde46fa9e9d9e0e5fb3c22e6133916158b 100644 (file)
@@ -264,6 +264,7 @@ static enum resp_states get_srq_wqe(struct rxe_qp *qp)
        struct rxe_recv_wqe *wqe;
        struct ib_event ev;
        unsigned int count;
+       unsigned int num_sge;
        size_t size;
        unsigned long flags;
 
@@ -279,12 +280,13 @@ static enum resp_states get_srq_wqe(struct rxe_qp *qp)
        }
 
        /* don't trust user space data */
-       if (unlikely(wqe->dma.num_sge > srq->rq.max_sge)) {
+       num_sge = wqe->dma.num_sge;
+       if (unlikely(num_sge > srq->rq.max_sge)) {
                spin_unlock_irqrestore(&srq->rq.consumer_lock, flags);
                rxe_dbg_qp(qp, "invalid num_sge in SRQ entry\n");
                return RESPST_ERR_MALFORMED_WQE;
        }
-       size = sizeof(*wqe) + wqe->dma.num_sge*sizeof(struct rxe_sge);
+       size = sizeof(*wqe) + num_sge * sizeof(struct rxe_sge);
        memcpy(&qp->resp.srq_wqe, wqe, size);
 
        qp->resp.wqe = &qp->resp.srq_wqe.wqe;