From: Tristan Madani <tristmd@gmail.com>
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, Moni Shoua <monis@mellanox.com>,
Tristan Madani <tristan@talencesecurity.com>
Subject: [PATCH v3 2/2] RDMA/rxe: copy send WQE to kernel buffer in completer path
Date: Wed, 7 Oct 2026 21:27:37 +0000 [thread overview]
Message-ID: <20261007212737.1989004-3-tristmd@gmail.com> (raw)
In-Reply-To: <20261007212737.1989004-1-tristmd@gmail.com>
From: Tristan Madani <tristan@talencesecurity.com>
The rxe completer processes send Work Queue Entries (WQEs) directly
from the mmap'd shared send queue without copying them to kernel memory.
Userspace can modify WQE fields (num_sge, opcode, PSN values, DMA state)
while the completer is processing them, leading to inconsistent
decisions in check_psn() and check_ack(), and potential out-of-bounds
access in copy_data() via a corrupted dma.num_sge.
This is the completer-path counterpart to the previous commit which
fixed the requester path.
Fix by copying the WQE to a kernel-private buffer in get_wqe() before
processing. The local copy is reused across multi-packet operations
(e.g. RDMA READ responses) when the WQE state is unchanged, preserving
DMA progress across completer invocations. The copy is refreshed when
the state changes (via smp_load_acquire pairing with the requester
smp_store_release) to ensure PSN and other fields are consistent.
Field updates (status, has_rd_atomic) are written back to the shared
queue using WRITE_ONCE() before advancing the consumer pointer, so
userspace observes consistent completion values.
Fixes: 8700e3e7c485 ("Soft RoCE driver")
Cc: stable@vger.kernel.org
Signed-off-by: Tristan Madani <tristan@talencesecurity.com>
---
drivers/infiniband/sw/rxe/rxe_comp.c | 54 ++++++++++++++++++++++++++-
drivers/infiniband/sw/rxe/rxe_verbs.h | 6 +++
2 files changed, 58 insertions(+), 2 deletions(-)
diff --git a/drivers/infiniband/sw/rxe/rxe_comp.c b/drivers/infiniband/sw/rxe/rxe_comp.c
index 1390e861bd1d7..f57c4396c28cb 100644
--- a/drivers/infiniband/sw/rxe/rxe_comp.c
+++ b/drivers/infiniband/sw/rxe/rxe_comp.c
@@ -88,6 +88,18 @@ static inline unsigned long rnrnak_jiffies(u8 timeout)
usecs_to_jiffies(rnrnak_usec[timeout]), 1);
}
+static void rxe_comp_writeback_wqe(struct rxe_qp *qp)
+{
+ struct rxe_send_wqe *shared = qp->comp.shared_wqe;
+ struct rxe_send_wqe *local = &qp->comp.comp_wqe.wqe;
+
+ if (!qp->comp.comp_wqe_valid || !shared)
+ return;
+
+ WRITE_ONCE(shared->status, local->status);
+ WRITE_ONCE(shared->has_rd_atomic, local->has_rd_atomic);
+}
+
static enum ib_wc_opcode wr_to_wc_opcode(enum ib_wr_opcode opcode)
{
switch (opcode) {
@@ -142,17 +154,52 @@ static inline enum comp_state get_wqe(struct rxe_qp *qp,
struct rxe_send_wqe **wqe_p)
{
struct rxe_send_wqe *wqe;
+ u32 state;
+ unsigned int num_sge;
/* we come here whether or not we found a response packet to see if
* there are any posted WQEs
*/
wqe = queue_head(qp->sq.queue, QUEUE_TYPE_FROM_CLIENT);
- *wqe_p = wqe;
/* no WQE or requester has not started it yet */
- if (!wqe || wqe->state == wqe_state_posted)
+ if (!wqe) {
+ *wqe_p = NULL;
return pkt ? COMPST_DONE : COMPST_EXIT;
+ }
+ /* Pairs with smp_store_release() in rxe_req_writeback_wqe() */
+ state = smp_load_acquire(&wqe->state);
+ if (state == wqe_state_posted) {
+ *wqe_p = wqe;
+ return pkt ? COMPST_DONE : COMPST_EXIT;
+ }
+
+ /* Reuse existing local copy if still processing same WQE
+ * with unchanged state (preserves DMA progress for multi-packet ops)
+ */
+ if (qp->comp.comp_wqe_valid && qp->comp.shared_wqe == wqe &&
+ qp->comp.comp_wqe.wqe.state == state) {
+ wqe = &qp->comp.comp_wqe.wqe;
+ *wqe_p = wqe;
+ goto check_state;
+ }
+
+ /* Copy shared WQE to kernel-private buffer */
+ num_sge = wqe->dma.num_sge;
+ if (unlikely(num_sge > RXE_MAX_SGE))
+ num_sge = RXE_MAX_SGE;
+
+ qp->comp.shared_wqe = wqe;
+ memcpy(&qp->comp.comp_wqe.wqe, wqe,
+ sizeof(*wqe) + num_sge * sizeof(struct rxe_sge));
+ qp->comp.comp_wqe_valid = true;
+ qp->comp.comp_wqe.wqe.dma.num_sge = num_sge;
+
+ wqe = &qp->comp.comp_wqe.wqe;
+ *wqe_p = wqe;
+
+check_state:
/* WQE does not require an ack */
if (wqe->state == wqe_state_done)
return COMPST_COMP_WQE;
@@ -454,6 +501,9 @@ static void do_complete(struct rxe_qp *qp, struct rxe_send_wqe *wqe)
if (post)
make_send_cqe(qp, wqe, &cqe);
+ rxe_comp_writeback_wqe(qp);
+ qp->comp.comp_wqe_valid = false;
+
queue_advance_consumer(qp->sq.queue, QUEUE_TYPE_FROM_CLIENT);
if (post)
diff --git a/drivers/infiniband/sw/rxe/rxe_verbs.h b/drivers/infiniband/sw/rxe/rxe_verbs.h
index a22dfc6e5ae3c..6205dbc29dff6 100644
--- a/drivers/infiniband/sw/rxe/rxe_verbs.h
+++ b/drivers/infiniband/sw/rxe/rxe_verbs.h
@@ -130,6 +130,12 @@ struct rxe_comp_info {
int started_retry;
u32 retry_cnt;
u32 rnr_retry;
+ struct rxe_send_wqe *shared_wqe;
+ bool comp_wqe_valid;
+ struct {
+ struct rxe_send_wqe wqe;
+ struct ib_sge sge[RXE_MAX_SGE];
+ } comp_wqe;
};
/* responder states */
--
2.47.3
prev parent reply other threads:[~2026-10-07 21:27 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-07 21:27 [PATCH v3 0/2] RDMA/rxe: Fix TOCTOU races on mmap'd send queue Tristan Madani
2026-10-07 21:27 ` [PATCH v3 1/2] RDMA/rxe: copy send WQE to kernel buffer before processing Tristan Madani
2026-10-07 21:27 ` Tristan Madani [this message]
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=20261007212737.1989004-3-tristmd@gmail.com \
--to=tristmd@gmail.com \
--cc=jgg@ziepe.ca \
--cc=leon@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-rdma@vger.kernel.org \
--cc=monis@mellanox.com \
--cc=stable@vger.kernel.org \
--cc=tristan@talencesecurity.com \
--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 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®