All of lore.kernel.org
 help / color / mirror / Atom feed
From: Ibrahim Hashimov <security@auditcode.ai>
To: Zhu Yanjun <zyjzyj2000@gmail.com>, Jason Gunthorpe <jgg@ziepe.ca>,
	Leon Romanovsky <leon@kernel.org>
Cc: linux-rdma@vger.kernel.org, linux-kernel@vger.kernel.org,
	stable@vger.kernel.org
Subject: [PATCH] RDMA/rxe: fix responder UAF on IB_QP_MAX_DEST_RD_ATOMIC modify_qp
Date: Thu,  9 Jul 2026 00:45:50 +0200	[thread overview]
Message-ID: <20260708224550.1281-1-security@auditcode.ai> (raw)

rxe_qp_from_attr()'s IB_QP_MAX_DEST_RD_ATOMIC branch frees and
reallocates qp->resp.resources[] (the rd_atomic resource array used by
the responder to track in-flight RDMA READ/ATOMIC/FLUSH requests)
completely outside of the IB_QP_STATE handling above it. Unlike every
other place that tears this array down -- rxe_qp_reset(), reached only
under IB_QP_STATE, always calls rxe_disable_task(&qp->recv_task) /
rxe_disable_task(&qp->send_task) to drain the responder and requester
tasks before touching per-QP state, then re-enables them -- this branch
runs with the responder task (rxe_receiver(), scheduled as recv_task on
the rxe_wq workqueue) fully live and unlocked. A userspace modify_qp()
that sets only IB_QP_MAX_DEST_RD_ATOMIC (no state change, so
__qp_chk_state()/ib_modify_qp_is_ok() never runs and qp->state_lock is
never taken here) can therefore race the responder in two ways:

 1. free_rd_atomic_resources() calls kfree(qp->resp.resources) and
    alloc_rd_atomic_resources() kzalloc_objs()'s a new array while
    rxe_prepare_res()/find_resource() in rxe_resp.c are concurrently
    walking &qp->resp.resources[i] with no lock held -- a straight
    free-vs-read race on the array itself.

 2. free_rd_atomic_resources() only NULLs qp->resp.resources; it never
    clears qp->resp.res, the raw pointer *into* that array that
    rxe_resp.c caches across a multi-packet RDMA READ/ATOMIC/FLUSH
    reply (set at rxe_resp.c read/atomic/flush-reply sites, cleared
    only on the normal completion paths). If a modify_qp() races a
    resource still referenced by qp->resp.res, the array is freed out
    from under the cached pointer and the next reply packet dereferences
    it -- independent of the kfree/kzalloc_objs() window in (1).

Reproduced with KASAN: a single process driving one RC QP pair in rxe
loopback, one thread pumping large multi-packet IBV_WR_RDMA_READs
against qpB while a second thread hammers
ibv_modify_qp(qpB, IB_QP_MAX_DEST_RD_ATOMIC), reliably (~11s) produces

  BUG: KASAN: slab-use-after-free in rxe_receiver+0x4f78/0x89e0 [rdma_rxe]
  Workqueue: rxe_wq do_work [rdma_rxe]

with the freed kmalloc-1k object being the rd_atomic resource array
freed by the modify_qp() thread while the recv_task kworker reads it.
An identical run modifying only IB_QP_MIN_RNR_TIMER (no resource free)
is clean.

Fix both races the same way rxe_qp_reset() already handles tearing down
this exact array: quiesce the responder task around the free/realloc by
calling rxe_disable_task(&qp->recv_task) before free_rd_atomic_resources()
and rxe_enable_task(&qp->recv_task) after alloc_rd_atomic_resources(),
so rxe_receiver() cannot observe the array mid-free/mid-realloc. And
close the still-open window for (2) at the source: have
free_rd_atomic_resources() clear qp->resp.res along with
qp->resp.resources, exactly like the existing completion paths in
rxe_resp.c (check_rkey()/duplicate_request()/RESPST_CLEANUP) already do
when a resource's lifetime ends, so a drained-and-resumed responder
restarts at RESPST_CHK_PSN against the fresh array instead of replaying
a stale reference into the old one.

Only qp->recv_task is drained: qp->resp.resources / qp->resp.res are
touched exclusively by the responder (rxe_resp.c); the requester
(send_task / rxe_sender()) never reads them, so there is no need to
widen this beyond what rxe_qp_reset() would drain for the equivalent
state.

Verified on the same v6.19 KASAN stand: with this fix applied, the
identical differential reproducer drives sustained MAX_DEST_RD_ATOMIC
storms against qpB well past the ~11s pre-fix time-to-first-splat with
zero KASAN reports, versus reliably tripping the slab-use-after-free in
rxe_receiver() described above before the fix.

Fixes: 8700e3e7c485 ("Soft RoCE driver")
Cc: stable@vger.kernel.org
Signed-off-by: Ibrahim Hashimov <security@auditcode.ai>
Assisted-by: AuditCode-AI:2026.07
---
 drivers/infiniband/sw/rxe/rxe_qp.c | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/drivers/infiniband/sw/rxe/rxe_qp.c b/drivers/infiniband/sw/rxe/rxe_qp.c
index f3dff1aea96a..646957707765 100644
--- a/drivers/infiniband/sw/rxe/rxe_qp.c
+++ b/drivers/infiniband/sw/rxe/rxe_qp.c
@@ -172,6 +172,7 @@ static void free_rd_atomic_resources(struct rxe_qp *qp)
 		}
 		kfree(qp->resp.resources);
 		qp->resp.resources = NULL;
+		qp->resp.res = NULL;
 	}
 }
 
@@ -709,9 +710,15 @@ int rxe_qp_from_attr(struct rxe_qp *qp, struct ib_qp_attr *attr, int mask,
 
 		qp->attr.max_dest_rd_atomic = max_dest_rd_atomic;
 
+		/*
+		 * Not gated by IB_QP_STATE above: quiesce the responder task
+		 * the same way rxe_qp_reset() does before touching this
+		 * array, so rxe_receiver() can't race the free/realloc.
+		 */
+		rxe_disable_task(&qp->recv_task);
 		free_rd_atomic_resources(qp);
-
 		err = alloc_rd_atomic_resources(qp, max_dest_rd_atomic);
+		rxe_enable_task(&qp->recv_task);
 		if (err)
 			return err;
 	}
-- 
2.50.1 (Apple Git-155)


             reply	other threads:[~2026-07-08 22:46 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-07-08 22:45 Ibrahim Hashimov [this message]
2026-07-09  1:22 ` [PATCH] RDMA/rxe: fix responder UAF on IB_QP_MAX_DEST_RD_ATOMIC modify_qp yanjun.zhu
2026-07-09  7:22   ` Ibrahim Hashimov
2026-07-09  7:26 ` [PATCH v2] " Ibrahim Hashimov
2026-07-09 18:24   ` yanjun.zhu
2026-07-12  8:58     ` Leon Romanovsky

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260708224550.1281-1-security@auditcode.ai \
    --to=security@auditcode.ai \
    --cc=jgg@ziepe.ca \
    --cc=leon@kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-rdma@vger.kernel.org \
    --cc=stable@vger.kernel.org \
    --cc=zyjzyj2000@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.