From: sashiko-bot@kernel.org
To: "Yishai Hadas" <yishaih@nvidia.com>
Cc: linux-rdma@vger.kernel.org
Subject: Re: [PATCH rdma-next 12/23] RDMA/mlx5: Verify UMR CQ polling against a hostile NIC
Date: Wed, 04 Nov 2026 16:43:47 +0000 [thread overview]
Message-ID: <sashiko-outbox-197665@kernel.org> (raw)
In-Reply-To: <20261103163949.1554-13-yishaih@nvidia.com>
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [Critical] RDMA/mlx5: unvalidated error CQE syndromes in mlx5_ib_poll_one_umr()
- [High] RDMA/mlx5: hung UMR waiters in mlx5_ib_poll_one_umr() on teardown
--
commit da9b5d87a1b071b4bd6eacadaf91a72df89f8c23
Author: Yishai Hadas <yishaih@nvidia.com>
RDMA/mlx5: Verify UMR CQ polling against a hostile NIC
This commit adds a dedicated UMR CQ polling handler in adversarial mode
that validates incoming CQEs against a shadow FIFO of posted UMR requests
and triggers forced health recovery if a forged CQE is detected.
> diff --git a/drivers/infiniband/hw/mlx5/cq.c b/drivers/infiniband/hw/mlx5/cq.c
> index 11c1153747c24..1a98263ec3111 100644
> --- a/drivers/infiniband/hw/mlx5/cq.c
> +++ b/drivers/infiniband/hw/mlx5/cq.c
[ ... ]
> @@ -608,6 +609,161 @@ static int poll_soft_wc(struct mlx5_ib_cq *cq, int num_entries,
> return npolled;
> }
>
> +static int mlx5_ib_poll_one_stopped(struct mlx5_ib_cq *cq,
> + struct mlx5_ib_qp **cur_qp, struct ib_wc *wc)
> +{
> + return -EAGAIN;
> +}
[ ... ]
> +int mlx5_ib_poll_one_umr(struct mlx5_ib_cq *cq, struct mlx5_ib_qp **cur_qp,
> + struct ib_wc *wc)
> +{
[ ... ]
> + /* Pop the shadow FIFO head: validated, dispatch to its waiter */
> + WRITE_ONCE(umrc->pending[head & (MLX5_UMR_MAX_WR - 1)], NULL);
> + umrc->pending_head = head + 1;
> + wc->wr_cqe = &expected->cqe;
> +
> + wc->qp = &qp->ibqp;
> + wq->tail = wq->wqe_head[idx] + 1;
> + /* Advance wq->last_poll, the internal error flush starts from it */
> + handle_atomics(qp, cqe64, wq->last_poll, idx);
> +
> + if (opcode == MLX5_CQE_REQ) {
> + wc->status = IB_WC_SUCCESS;
> + } else {
> + /* Copy the CQE, so its syndrome is read once */
> + err_cqe = *(struct mlx5_err_cqe *)cqe64;
> + mlx5_handle_error_cqe(dev, &err_cqe, wc);
> + /* As in the generic path, a real failure starts the recovery */
> + if (wc->status != IB_WC_WR_FLUSH_ERR)
> + umrc->state = MLX5_UMR_STATE_RECOVER;
> + }
[Severity: Critical]
Does mlx5_ib_poll_one_umr() need to validate whether the error syndrome in a
MLX5_CQE_REQ_ERR completion is valid for the current umrc->state?
If umrc->state is MLX5_UMR_STATE_ACTIVE and a hostile NIC reports
MLX5_CQE_SYNDROME_WR_FLUSH_ERR for the oldest pending UMR WQE,
mlx5_ib_poll_one_umr() completes the request with IB_WC_WR_FLUSH_ERR while
leaving umrc->state as MLX5_UMR_STATE_ACTIVE. In
drivers/infiniband/hw/mlx5/umr.c:mlx5r_umr_post_send_wait(), the waiter sees
IB_WC_WR_FLUSH_ERR, continues the loop, sees umrc->state is still
MLX5_UMR_STATE_ACTIVE, and reposts the WQE indefinitely.
Conversely, when multiple UMR requests are in flight concurrently and the NIC
returns a non-flush error syndrome for more than one of them, each of those
waiters wakes up in mlx5r_umr_post_send_wait() with a status other than
IB_WC_WR_FLUSH_ERR and calls mlx5r_umr_recover(). Because mlx5r_umr_recover()
drops umrc->lock before posting the barrier WR and resetting the QP:
drivers/infiniband/hw/mlx5/umr.c:mlx5r_umr_recover()
mutex_unlock(&umrc->lock);
err = mlx5r_umr_post_send(umrc->qp, mkey, umr_context, wqe, with_data);
...
wait_for_completion(&umr_context->done);
attr.qp_state = IB_QPS_RESET;
err = ib_modify_qp(umrc->qp, &attr, IB_QP_STATE);
multiple threads can enter recovery concurrently. When the first thread
resets the QP via __mlx5_ib_modify_qp(), qp->sq.head, qp->sq.tail,
qp->sq.cur_post, and qp->sq.last_poll are zeroed while the second thread's
barrier WR remains in umrc->pending with a non-zero wq->wqe_head[idx].
Completing that second barrier WR then sets wq->tail = wq->wqe_head[idx] + 1
while wq->head is 0. If a subsequent forged CQE triggers internal error
flushing, sw_comp() computes cur = wq->head - wq->tail (which wraps around as
unsigned int) and completes stale wq->wrid[] entries pointing to
stack-allocated mlx5r_umr_context structures of callers that have already
returned.
Should a flush error while active, or a second non-flush error after
entering recovery, be treated as a forged CQE (or should error CQEs on the
UMR QP be disallowed altogether in adversarial mode)?
> +
> + return 0;
> +
> +forged_cqe:
> + /* mlx5_ib_poll_cq() updates the CI only for a returned completion */
> + mlx5_cq_set_ci(&cq->mcq);
> + /*
> + * The NIC forged a CQE. Fail the UMR path for good, ignore any later
> + * CQE and force the health recovery, as the fatal sensors still read
> + * clean. The internal error flush then completes the waiters. Return
> + * an error, not -EAGAIN, as a CQE was consumed.
> + */
> + umrc->state = MLX5_UMR_STATE_ERR;
> + cq->poll_one = mlx5_ib_poll_one_stopped;
> + mlx5_trigger_health_work_force(dev->mdev);
> + return -EIO;
> +}
[Severity: High]
Can relying solely on mlx5_trigger_health_work_force() to flush pending UMR
requests leave waiters in mlx5r_umr_post_send_wait() hung during device
teardown, reload, or removal?
During teardown or reload, mlx5_unload_one_devl_locked() and
mlx5_uninit_one() in drivers/net/ethernet/mellanox/mlx5/core/main.c hold
dev->intf_state_mutex while unregistering the IB device, which revokes open
MRs through:
mlx5_ib_dereg_mr()
-> mlx5r_handle_mkey_cleanup()
-> mlx5_umr_revoke_mr_with_lock()
-> mlx5r_umr_revoke_mr()
-> mlx5r_umr_post_send_wait()
In addition, remove_one(), shutdown(), and
mlx5_sync_reset_set_reset_requested() call mlx5_drain_health_wq() or
mlx5_stop_health_poll(), setting MLX5_DROP_HEALTH_WORK before mlx5_ib
teardown finishes.
If a forged CQE is detected in mlx5_ib_poll_one_umr() during these flows,
cq->poll_one is replaced with mlx5_ib_poll_one_stopped without completing
the entries in umrc->pending. The queued force_fatal_report_work calls
mlx5_fw_fatal_reporter_err() in
drivers/net/ethernet/mellanox/mlx5/core/health.c:
mutex_lock(&dev->intf_state_mutex);
if (test_bit(MLX5_DROP_HEALTH_WORK, &health->flags)) {
mlx5_core_err(dev, "health works are not permitted at this stage\n");
mutex_unlock(&dev->intf_state_mutex);
return;
}
Because dev->intf_state_mutex is held by the thread waiting in
wait_for_completion(&umr_context.done), or because MLX5_DROP_HEALTH_WORK is
already set, enter_error_state() and the software CQ flush cannot run,
leaving the UMR waiters blocked forever. Could forged_cqe drain and complete
the remaining contexts in umrc->pending directly?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261103163949.1554-1-yishaih@nvidia.com?part=12
next prev parent reply other threads:[~2026-11-04 16:43 UTC|newest]
Thread overview: 51+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-03 16:39 [PATCH rdma-next 00/23] mlx5: Adversarial mode for confidential computing guests Yishai Hadas
2026-11-03 16:39 ` [PATCH rdma-next 01/23] net/mlx5: Add mlx5_trigger_health_work_force() Yishai Hadas
2026-11-04 16:43 ` sashiko-bot
2026-11-03 16:39 ` [PATCH rdma-next 02/23] net/mlx5: Derive adversarial mode from CC guest memory encryption Yishai Hadas
2026-11-04 16:43 ` sashiko-bot
2026-11-03 16:39 ` [PATCH rdma-next 03/23] net/mlx5: Add capability filtering in adversarial mode Yishai Hadas
2026-11-04 16:43 ` sashiko-bot
2026-11-05 14:50 ` Yishai Hadas
2026-11-03 16:39 ` [PATCH rdma-next 04/23] net/mlx5: Add macros for reading log-based caps Yishai Hadas
2026-11-04 16:43 ` sashiko-bot
2026-11-03 16:39 ` [PATCH rdma-next 05/23] RDMA/mlx5: Reject QP transport types not enabled by FW capability Yishai Hadas
2026-11-04 16:43 ` sashiko-bot
2026-11-03 16:39 ` [PATCH rdma-next 06/23] RDMA/mlx5: Require IB_QPT_DRIVER for the DC vendor QP types Yishai Hadas
2026-11-04 16:43 ` sashiko-bot
2026-11-03 16:39 ` [PATCH rdma-next 07/23] RDMA/mlx5: Derive mlx5_ib_adversarial_mode global from mlx5_core adversarial API Yishai Hadas
2026-11-04 16:43 ` sashiko-bot
2026-11-03 16:39 ` [PATCH rdma-next 08/23] RDMA/core: Suppress kverbs_provider for adversarial_mode devices Yishai Hadas
2026-11-03 19:03 ` Jacob Moroni
2026-11-03 19:07 ` Jason Gunthorpe
2026-11-04 16:43 ` sashiko-bot
2026-11-03 16:39 ` [PATCH rdma-next 09/23] RDMA/mlx5: Remove duplicate mlx5_ib_umr_context struct Yishai Hadas
2026-11-04 16:43 ` sashiko-bot
2026-11-03 16:39 ` [PATCH rdma-next 10/23] RDMA/mlx5: Introduce per-CQ poll_one hook in mlx5_ib_cq Yishai Hadas
2026-11-04 16:43 ` sashiko-bot
2026-11-03 16:39 ` [PATCH rdma-next 11/23] RDMA/mlx5: Add shadow FIFO infrastructure for UMR completions Yishai Hadas
2026-11-04 16:43 ` sashiko-bot
2026-11-03 16:39 ` [PATCH rdma-next 12/23] RDMA/mlx5: Verify UMR CQ polling against a hostile NIC Yishai Hadas
2026-11-04 16:43 ` sashiko-bot [this message]
2026-11-05 16:46 ` Yishai Hadas
2026-11-03 16:39 ` [PATCH rdma-next 13/23] RDMA/mlx5: Keep the UMR QP failed once a forged CQE is detected Yishai Hadas
2026-11-04 16:43 ` sashiko-bot
2026-11-03 16:39 ` [PATCH rdma-next 14/23] RDMA/mlx5: Block generic CQ poll path in adversarial mode Yishai Hadas
2026-11-04 16:43 ` sashiko-bot
2026-11-03 16:39 ` [PATCH rdma-next 15/23] RDMA/core: Set the CQ comp_handler after its poll context is set up Yishai Hadas
2026-11-04 16:43 ` sashiko-bot
2026-11-03 16:39 ` [PATCH rdma-next 16/23] RDMA/mlx5: Ignore completion events for a CQ without a handler Yishai Hadas
2026-11-04 16:43 ` sashiko-bot
2026-11-03 16:39 ` [PATCH rdma-next 17/23] RDMA/mlx5: Validate EQE port and GSI port before indexing devr.ports[] Yishai Hadas
2026-11-04 16:43 ` sashiko-bot
2026-11-03 16:39 ` [PATCH rdma-next 18/23] RDMA/mlx5: Validate firmware RQ/SQ state before sqrq_trans[] lookup Yishai Hadas
2026-11-04 16:43 ` sashiko-bot
2026-11-03 16:39 ` [PATCH rdma-next 19/23] RDMA/mlx5: Clamp log_max_cq_sz shift in CQ size checks Yishai Hadas
2026-11-04 16:43 ` sashiko-bot
2026-11-03 16:39 ` [PATCH rdma-next 20/23] RDMA/mlx5: Clamp log_max_* shifts in QP and WQ limit checks Yishai Hadas
2026-11-04 16:43 ` sashiko-bot
2026-11-03 16:39 ` [PATCH rdma-next 21/23] RDMA/mlx5: Clamp log_max_* shifts in query_device and ucontext paths Yishai Hadas
2026-11-04 16:43 ` sashiko-bot
2026-11-03 16:39 ` [PATCH rdma-next 22/23] RDMA/core: Report and enforce adversarial mode via GET_CONTEXT Yishai Hadas
2026-11-04 16:43 ` sashiko-bot
2026-11-03 16:39 ` [PATCH rdma-next 23/23] RDMA/mlx5: Advertise adversarial mode via ib_device::adversarial_mode Yishai Hadas
2026-11-04 16:43 ` 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=sashiko-outbox-197665@kernel.org \
--to=sashiko-bot@kernel.org \
--cc=linux-rdma@vger.kernel.org \
--cc=sashiko-reviews@lists.linux.dev \
--cc=yishaih@nvidia.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.