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
next prev parent reply other threads:[~2026-10-07 21:27 UTC|newest]
Thread overview: 5+ 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:40 ` sashiko-bot
2026-10-07 21:27 ` Tristan Madani [this message]
2026-10-07 21:49 ` [PATCH v3 2/2] RDMA/rxe: copy send WQE to kernel buffer in completer path sashiko-bot
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 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.