From: Tristan Madani <tristmd@gmail.com>
To: linux-rdma@vger.kernel.org
Cc: jgg@ziepe.ca, leon@kernel.org, zyjzyj2000@gmail.com,
bob.pearson@hpe.com, Tristan Madani <tristan@talencesecurity.com>,
stable@vger.kernel.org
Subject: [PATCH v4 2/2] RDMA/rxe: copy send WQE to kernel buffer in completer path
Date: Wed, 7 Oct 2026 22:32:22 +0000 [thread overview]
Message-ID: <20261007223222.2342804-3-tristmd@gmail.com> (raw)
In-Reply-To: <20261007223222.2342804-1-tristmd@gmail.com>
From: Tristan Madani <tristan@talencesecurity.com>
The completer reads send WQEs from the same userspace-mapped shared
queue as the requester. Even after the requester copies the WQE to a
kernel-private buffer (previous patch), the completer still reads
directly from shared memory, leaving it exposed to the same TOCTOU
races.
Fix by copying the WQE in get_wqe() to a completer-private buffer
using the full queue element size (max_sge SGEs). The local copy is
reused when the same WQE is being processed with unchanged state,
which preserves DMA progress across multi-packet RDMA READ responses.
A fresh copy is taken when the state changes or a new WQE appears.
State transitions from the requester are observed through an
smp_load_acquire() / smp_store_release() pair. Completion status and
rd_atomic state are written back through WRITE_ONCE() before the
consumer index advances.
The copy is invalidated on QP reset and when the completion advances
to the next WQE.
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 | 53 ++++++++++++++++++++++++++-
drivers/infiniband/sw/rxe/rxe_qp.c | 1 +
drivers/infiniband/sw/rxe/rxe_verbs.h | 6 +++
3 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..ca31093fdf3aa 100644
--- a/drivers/infiniband/sw/rxe/rxe_comp.c
+++ b/drivers/infiniband/sw/rxe/rxe_comp.c
@@ -137,22 +137,69 @@ void rxe_comp_queue_pkt(struct rxe_qp *qp, struct sk_buff *skb)
rxe_sched_task(&qp->send_task);
}
+/* Write back completer WQE fields to shared memory */
+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 inline enum comp_state get_wqe(struct rxe_qp *qp,
struct rxe_pkt_info *pkt,
struct rxe_send_wqe **wqe_p)
{
struct rxe_send_wqe *wqe;
+ u32 state;
/* 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. Copy the full
+ * element (max_sge SGEs) so that inline data, which shares
+ * the flex array with SGEs, is always captured.
+ */
+ qp->comp.shared_wqe = wqe;
+ memcpy(&qp->comp.comp_wqe.wqe, wqe,
+ sizeof(*wqe) + qp->sq.max_sge * sizeof(struct rxe_sge));
+ qp->comp.comp_wqe_valid = true;
+ if (qp->comp.comp_wqe.wqe.dma.num_sge > qp->sq.max_sge)
+ qp->comp.comp_wqe.wqe.dma.num_sge = qp->sq.max_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,8 @@ 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_qp.c b/drivers/infiniband/sw/rxe/rxe_qp.c
index 77606c4a039b1..450254a131017 100644
--- a/drivers/infiniband/sw/rxe/rxe_qp.c
+++ b/drivers/infiniband/sw/rxe/rxe_qp.c
@@ -582,6 +582,7 @@ static void rxe_qp_reset(struct rxe_qp *qp)
qp->req.wait_for_rnr_timer = 0;
qp->req.noack_pkts = 0;
qp->req.send_wqe_valid = false;
+ qp->comp.comp_wqe_valid = false;
qp->resp.msn = 0;
qp->resp.opcode = -1;
qp->resp.drop_msg = 0;
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 22:32 UTC|newest]
Thread overview: 13+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-07 22:32 [PATCH v4 0/2] RDMA/rxe: fix TOCTOU races in send WQE processing Tristan Madani
2026-10-07 22:32 ` [PATCH v4 1/2] RDMA/rxe: copy send WQE to kernel buffer before processing Tristan Madani
2026-10-07 22:47 ` sashiko-bot
2026-10-07 22:32 ` Tristan Madani [this message]
2026-10-07 22:48 ` [PATCH v4 2/2] RDMA/rxe: copy send WQE to kernel buffer in completer path sashiko-bot
2026-10-08 5:11 ` [PATCH v4 0/2] RDMA/rxe: fix TOCTOU races in send WQE processing Zhu Yanjun
2026-10-08 12:01 ` Tristan Madani
2026-10-08 19:34 ` Zhu Yanjun
2026-10-08 9:37 ` [PATCH v5 0/2] RDMA/rxe: fix send-path TOCTOU races on shared WQEs Tristan Madani
2026-10-08 9:37 ` [PATCH v5 1/2] RDMA/rxe: copy send WQE to kernel buffer before processing Tristan Madani
2026-10-08 9:54 ` sashiko-bot
2026-10-08 9:37 ` [PATCH v5 2/2] RDMA/rxe: copy send WQE to kernel buffer in completer path Tristan Madani
2026-10-08 9:55 ` 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=20261007223222.2342804-3-tristmd@gmail.com \
--to=tristmd@gmail.com \
--cc=bob.pearson@hpe.com \
--cc=jgg@ziepe.ca \
--cc=leon@kernel.org \
--cc=linux-rdma@vger.kernel.org \
--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.