From: sashiko-bot@kernel.org
To: "Xin Tian" <tianx@yunsilicon.com>
Cc: linux-rdma@vger.kernel.org
Subject: Re: [PATCH 05/15] yunsilicon: add the CQ and QP resource pools
Date: Tue, 13 Oct 2026 11:46:09 +0000 [thread overview]
Message-ID: <sashiko-outbox-169642@kernel.org> (raw)
In-Reply-To: <20261012114402.2471317-6-tianx@yunsilicon.com>
Thank you for your contribution! Sashiko AI review found 8 potential issue(s) to consider:
- [High] networking-core: UAF in xsc_cq_completion due to missing RCU grace period
- [High] networking-drivers: Race condition exposing uninitialized QP state and NULL callbacks
- [High] networking-core: RCU Use-After-Free in xsc_cq_completion due to missing synchronize_rcu()
- [High] Infinite loop in xsc_set_cq_buf_pa if max_cmd_in_len is small
- [Medium] networking-drivers: Resource leak and synchronization bypass on HW teardown error
- [Medium] networking-drivers: Dead code and masked HW errors due to xsc_cmd_exec status override
- [Medium] networking-drivers: in_hdr->ver is unconditionally zeroed out in xsc_cmd_exec
- [Low] networking-drivers: Endianness mismatch printing __be16 with %d
--
commit 395a471908d4219d4c81557da37b36e1a6d0b7d1
Author: Xin Tian <tianx@yunsilicon.com>
yunsilicon: add the CQ and QP resource pools
Add the core-side completion queue and queue pair pools: the CQ/QP
table management, the create/destroy/drain helpers and the EQ dispatch
of CQ completion, CQ error and QP events.
> diff --git a/drivers/net/ethernet/yunsilicon/xsc/pci/cq.c b/drivers/net/ethernet/yunsilicon/xsc/pci/cq.c
> new file mode 100644
> index 0000000000000..39715682fecc3
> --- /dev/null
> +++ b/drivers/net/ethernet/yunsilicon/xsc/pci/cq.c
[ ... ]
> +static int xsc_set_cq_context(struct xsc_core_device *xdev,
> + struct xsc_cq_context_ex *ctx_ex,
> + u32 *pa_list_base, u32 *cqn)
> +{
> + struct xsc_set_cq_context_mbox_in in;
> + struct xsc_set_cq_context_mbox_out out;
> + int err;
> +
> + memset(&in, 0, sizeof(in));
> + memcpy(&in.ctx_ex, ctx_ex, sizeof(*ctx_ex));
> + in.hdr.opcode = cpu_to_be16(XSC_CMD_OP_SET_CQ_CONTEXT);
> + in.hdr.ver = cpu_to_be16(CMD_SET_CQ_CONTEXT_V1);
> +
> + memset(&out, 0, sizeof(out));
> + err = xsc_cmd_exec(xdev, &in, sizeof(in), &out, sizeof(out));
[Severity: Medium]
Does xsc_cmd_exec() preserve the version parameter set here? It looks like
xsc_cmd_exec() might unconditionally zero out in_hdr->ver before dispatching
the command to hardware, which would discard the CMD_SET_CQ_CONTEXT_V1 flag.
> + if (err || out.hdr.status) {
> + pci_err(xdev->pdev, "failed to set cq context\n");
> + return -EIO;
> + }
> +
> + *pa_list_base = be32_to_cpu(out.cq_pa_list_base);
> + *cqn = be32_to_cpu(out.cqn);
> + return 0;
> +}
> +
> +static int xsc_set_cq_buf_pa(struct xsc_core_device *xdev,
> + struct xsc_create_cq_ex_mbox_in *req,
> + u32 pa_list_base, u32 cqn)
> +{
> + struct xsc_set_cq_buf_pa_mbox_in *in;
> + struct xsc_set_cq_buf_pa_mbox_out out;
> + u32 pa_num_total = be32_to_cpu(req->ctx_ex.pa_num_ex);
> + u32 pa_num_max = (xdev->caps.max_cmd_in_len - sizeof(*in)) / sizeof(__be64);
> + u32 pa_num_left = pa_num_total;
> + u32 pa_num, copy_len;
> + int in_len, err;
> +
> + while (pa_num_left) {
> + pa_num = min(pa_num_max, pa_num_left);
[Severity: High]
Could this result in an infinite loop if the hardware returns a capability
where max_cmd_in_len is small (e.g., between 16 and 23)? pa_num_max would
evaluate to 0, causing pa_num to be 0. The loop would never decrement
pa_num_left and run infinitely. If max_cmd_in_len is < 16, the subtraction
might underflow to a massive unsigned value. Does xsc_cmd_query_hca_cap()
enforce a safe minimum bound?
> + copy_len = pa_num * sizeof(__be64);
> + in_len = sizeof(*in) + copy_len;
[ ... ]
> +int xsc_core_create_cq(struct xsc_core_device *xdev, struct xsc_core_cq *cq,
> + struct xsc_create_cq_ex_mbox_in *in, int inlen)
> +{
> + struct xsc_cq_table *table = &xdev->dev_res->cq_table;
> + struct xsc_create_cq_mbox_out out;
> + u32 pa_list_base = 0;
> + u32 cqn = 0;
> + int err;
> +
> + if (inlen < xdev->caps.max_cmd_in_len) {
> + in->hdr.opcode = cpu_to_be16(XSC_CMD_OP_CREATE_CQ_EX);
> + memset(&out, 0, sizeof(out));
> + err = xsc_cmd_exec(xdev, in, inlen, &out, sizeof(out));
> + if (err)
> + return err;
> +
> + if (out.hdr.status && out.hdr.status != XSC_CMD_STATUS_NOT_SUPPORTED)
> + return xsc_cmd_status_to_err(&out.hdr);
> +
> + if (out.hdr.status == XSC_CMD_STATUS_NOT_SUPPORTED) {
> + err = xsc_create_cq_compat(xdev, in, &out);
[Severity: Medium]
Will this compatibility fallback ever be reached? If xsc_cmd_exec() sees that
out_hdr->status is set, it might return -EIO directly, triggering the earlier
if (err) return err; block. This would make the check for
XSC_CMD_STATUS_NOT_SUPPORTED dead code and mask the specific firmware error.
> + if (err)
> + return err;
> + }
[ ... ]
> +int xsc_core_destroy_cq(struct xsc_core_device *xdev, struct xsc_core_cq *cq)
> +{
> + struct xsc_cq_table *table = &xdev->dev_res->cq_table;
> + struct xsc_destroy_cq_mbox_in in;
> + struct xsc_destroy_cq_mbox_out out;
> + struct xsc_core_cq *tmp;
> + int err;
> +
> + spin_lock_irq(&table->lock);
> + tmp = radix_tree_delete(&table->tree, cq->cqn);
> + spin_unlock_irq(&table->lock);
> + if (!tmp || tmp != cq) {
> + pci_warn(xdev->pdev, "cq 0x%x not found in tree\n", cq->cqn);
> + return -EINVAL;
> + }
> +
> + memset(&in, 0, sizeof(in));
> + memset(&out, 0, sizeof(out));
> + in.hdr.opcode = cpu_to_be16(XSC_CMD_OP_DESTROY_CQ);
> + in.cqn = cpu_to_be32(cq->cqn);
> +
> + err = xsc_cmd_exec(xdev, &in, sizeof(in), &out, sizeof(out));
> + if (err)
> + return err;
> +
> + if (out.hdr.status)
> + return xsc_cmd_status_to_err(&out.hdr);
[Severity: Medium]
If the hardware command fails, returning early here skips the refcount
decrement and the wait_for_completion() synchronization. Can this leak the
resource if the base reference is never dropped, or cause a use-after-free
for active concurrent event handlers if the caller frees the memory anyway?
[Severity: High]
Since the CQ is deleted from the RCU-protected radix tree above, shouldn't
there be a synchronize_rcu() or kfree_rcu() wait before returning? Without
an RCU grace period, concurrent lockless readers (like xsc_cq_completion)
might access the CQ structure after the caller frees the memory.
> +
> + if (atomic_dec_and_test(&cq->refcount))
> + complete(&cq->free);
> + wait_for_completion(&cq->free);
> +
> + return 0;
> +}
> +EXPORT_SYMBOL_GPL(xsc_core_destroy_cq);
> diff --git a/drivers/net/ethernet/yunsilicon/xsc/pci/eq.c b/drivers/net/ethernet/yunsilicon/xsc/pci/eq.c
> index d273a42d6ffe7..ff4bcb42b33ff 100644
> --- a/drivers/net/ethernet/yunsilicon/xsc/pci/eq.c
> +++ b/drivers/net/ethernet/yunsilicon/xsc/pci/eq.c
> @@ -53,16 +53,59 @@ static void eq_update_ci(struct xsc_eq *eq, int arm)
>
> static void xsc_cq_completion(struct xsc_core_device *xdev, u32 cqn)
> {
> + struct xsc_cq_table *table = &xdev->dev_res->cq_table;
> + struct xsc_core_cq *cq;
> +
> + rcu_read_lock();
> + cq = radix_tree_lookup(&table->tree, cqn);
> + if (likely(cq))
> + atomic_inc(&cq->refcount);
[Severity: High]
Is this lockless RCU lookup safe for an object being destroyed? The teardown
path in xsc_core_destroy_cq() deletes the CQ from the tree without waiting
for an RCU grace period. Additionally, shouldn't this use
atomic_inc_not_zero() instead of atomic_inc() to avoid resurrecting an
object that might already have its refcount at 0?
> + rcu_read_unlock();
[ ... ]
> +static void xsc_eq_cq_event(struct xsc_core_device *xdev,
> + u32 cqn, int event_type)
> +{
> + struct xsc_cq_table *table = &xdev->dev_res->cq_table;
> + struct xsc_core_cq *cq;
> +
> + spin_lock(&table->lock);
> + cq = radix_tree_lookup(&table->tree, cqn);
> + if (likely(cq))
> + atomic_inc(&cq->refcount);
> + spin_unlock(&table->lock);
> +
> + if (unlikely(!cq)) {
> + pci_err(xdev->pdev, "Async event for bogus CQ, cqn=%d\n",
> + cqn);
> + return;
> + }
> +
> + cq->event(cq, event_type);
[Severity: High]
Is it possible for cq->event to be NULL here? The CQ is added to the global
radix tree in xsc_core_create_cq() before the caller has a chance to
initialize the cq->event callback. If an interrupt arrives immediately, this
could cause a NULL pointer dereference.
> +
> + if (atomic_dec_and_test(&cq->refcount))
> + complete(&cq->free);
> }
>
> static int xsc_eq_int(struct xsc_core_device *xdev, struct xsc_eq *eq)
[ ... ]
> diff --git a/drivers/net/ethernet/yunsilicon/xsc/pci/qp.c b/drivers/net/ethernet/yunsilicon/xsc/pci/qp.c
> new file mode 100644
> index 0000000000000..8ea57a09f6ceb
> --- /dev/null
> +++ b/drivers/net/ethernet/yunsilicon/xsc/pci/qp.c
> @@ -0,0 +1,356 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/* Copyright (C) 2021-2026, Shanghai Yunsilicon Technology Co., Ltd.
> + * All rights reserved.
> + */
> +
> +#include <linux/gfp.h>
> +#include <linux/time.h>
> +#include <linux/export.h>
> +#include <linux/kthread.h>
> +
> +#include "common/xsc_core.h"
> +#include "common/xsc_cmd_api.h"
> +#include "qp.h"
> +
> +int xsc_core_create_resource_common(struct xsc_core_device *xdev,
> + struct xsc_core_qp *qp)
> +{
> + struct xsc_qp_table *table = &xdev->dev_res->qp_table;
> + int err;
> +
> + spin_lock_irq(&table->lock);
> + err = radix_tree_insert(&table->tree, qp->qpn, qp);
> + spin_unlock_irq(&table->lock);
> + if (err)
> + return err;
> +
> + atomic_set(&qp->refcount, 1);
> + init_completion(&qp->free);
[Severity: High]
Should the refcount and completion be initialized before the QP is inserted
into the radix tree? Once inserted, asynchronous event handlers like
xsc_qp_event() can look up the QP. If an event fires immediately, the
handler might execute atomic_inc(&qp->refcount) on uninitialized memory,
which is then clobbered by atomic_set() here.
> + qp->pid = current->pid;
> +
> + return 0;
> +}
[ ... ]
> +void xsc_qp_event(struct xsc_core_device *xdev, u32 qpn, int event_type)
> +{
> + struct xsc_qp_table *table = &xdev->dev_res->qp_table;
> + struct xsc_core_qp *qp;
> +
> + spin_lock(&table->lock);
> +
> + qp = radix_tree_lookup(&table->tree, qpn);
> + if (qp)
> + atomic_inc(&qp->refcount);
> +
> + spin_unlock(&table->lock);
> +
> + if (!qp) {
> + pci_err(xdev->pdev, "Async event for bogus QP 0x%x\n", qpn);
> + return;
> + }
> +
> + qp->event(qp, event_type);
[Severity: High]
Can qp->event be NULL here? The QP is published to the radix tree before the
caller initializes the qp->event function pointer. An early interrupt could
trigger a NULL pointer dereference.
> +
> + if (atomic_dec_and_test(&qp->refcount))
> + complete(&qp->free);
> +}
[ ... ]
> +int xsc_core_eth_create_rss_qp_rqs(struct xsc_core_device *xdev,
> + struct xsc_create_multiqp_mbox_in *in,
> + int insize,
> + u32 *p_qpn_base)
> +{
> + struct xsc_create_multiqp_mbox_out out;
> + int err;
> +
> + in->hdr.opcode = cpu_to_be16(XSC_CMD_OP_CREATE_MULTI_QP);
> + err = xsc_cmd_exec(xdev, in, insize, &out, sizeof(out));
> + if (err) {
> + pci_err(xdev->pdev,
> + "failed to create rss rq, qp_num=%d, type=%d, err=%d out.status=%u\n",
> + in->qp_num, in->qp_type, err, out.hdr.status);
[Severity: Low]
Is it intentional to pass in->qp_num directly to %d? Since in->qp_num is a
__be16 field, this will print garbled values on little-endian architectures
unless converted with be16_to_cpu().
> + return err;
> + }
[ ... ]
> +int xsc_core_destroy_qp(struct xsc_core_device *xdev,
> + struct xsc_core_qp *qp)
> +{
> + struct xsc_destroy_qp_mbox_in in;
> + struct xsc_destroy_qp_mbox_out out;
> + int err;
> +
> + xsc_core_destroy_resource_common(xdev, qp);
> +
> + memset(&in, 0, sizeof(in));
> + memset(&out, 0, sizeof(out));
> + in.hdr.opcode = cpu_to_be16(XSC_CMD_OP_DESTROY_QP);
> + in.qpn = cpu_to_be32(qp->qpn);
> +
> + err = xsc_cmd_exec(xdev, &in, sizeof(in), &out, sizeof(out));
> + if (err)
> + return err;
> +
> + if (out.hdr.status)
> + return xsc_cmd_status_to_err(&out.hdr);
[Severity: Medium]
Does returning early here skip decrementing the global active QP counter
(atomic_dec(&xdev->num_qps))? In xsc_core_create_qp(), num_qps is incremented
after resource creation, but a failure in the hardware destroy path seems
to leak this counter.
> +
> + atomic_dec(&xdev->num_qps);
> + return 0;
> +}
> +EXPORT_SYMBOL_GPL(xsc_core_destroy_qp);
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261012114352.2471317-1-tianx@yunsilicon.com?part=5
next prev parent reply other threads:[~2026-10-13 11:46 UTC|newest]
Thread overview: 35+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-12 11:44 [PATCH 00/15] Yunsilicon ethernet and RDMA drivers Xin Tian
2026-10-12 11:43 ` [PATCH 01/15] yunsilicon: add PCI core driver skeleton Xin Tian
2026-10-13 11:46 ` sashiko-bot
2026-10-12 11:43 ` [PATCH 02/15] yunsilicon: add the register HAL Xin Tian
2026-10-12 15:21 ` Andrew Lunn
2026-10-13 11:46 ` sashiko-bot
2026-10-12 11:43 ` [PATCH 03/15] yunsilicon: add the command queue Xin Tian
2026-10-13 3:11 ` Junxian Huang
2026-10-13 14:31 ` Leon Romanovsky
2026-10-13 11:46 ` sashiko-bot
2026-10-12 11:44 ` [PATCH 04/15] yunsilicon: add event queues, interrupts and the Xin Tian
2026-10-13 11:46 ` sashiko-bot
2026-10-12 11:44 ` [PATCH 05/15] yunsilicon: add the CQ and QP resource pools Xin Tian
2026-10-13 11:46 ` sashiko-bot [this message]
2026-10-12 11:44 ` [PATCH 06/15] yunsilicon: add ethernet netdev registration Xin Tian
2026-10-13 11:46 ` sashiko-bot
2026-10-12 11:44 ` [PATCH 07/15] yunsilicon: add ethernet TX path Xin Tian
2026-10-13 11:46 ` sashiko-bot
2026-10-12 11:44 ` [PATCH 08/15] yunsilicon: add ethernet RX path and statistics Xin Tian
2026-10-13 11:46 ` sashiko-bot
2026-10-12 11:44 ` [PATCH 09/15] yunsilicon: add RDMA device support Xin Tian
2026-10-13 6:17 ` Junxian Huang
2026-10-13 11:46 ` sashiko-bot
2026-10-12 11:44 ` [PATCH 10/15] yunsilicon: add RDMA PD/MR Xin Tian
2026-10-13 11:46 ` sashiko-bot
2026-10-12 11:44 ` [PATCH 11/15] yunsilicon: add RDMA CQ/SRQ/AH Xin Tian
2026-10-13 11:46 ` sashiko-bot
2026-10-12 11:44 ` [PATCH 12/15] yunsilicon: add RDMA QP verbs Xin Tian
2026-10-13 11:46 ` sashiko-bot
2026-10-12 11:44 ` [PATCH 13/15] yunsilicon: add the RDMA send path Xin Tian
2026-10-13 11:46 ` sashiko-bot
2026-10-12 11:44 ` [PATCH 14/15] yunsilicon: add RDMA counters and sysfs Xin Tian
2026-10-13 11:46 ` sashiko-bot
2026-10-12 11:44 ` [PATCH 15/15] MAINTAINERS: add the Yunsilicon XSC drivers Xin Tian
2026-10-13 14:34 ` [PATCH 00/15] Yunsilicon ethernet and RDMA drivers 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=sashiko-outbox-169642@kernel.org \
--to=sashiko-bot@kernel.org \
--cc=linux-rdma@vger.kernel.org \
--cc=sashiko-reviews@lists.linux.dev \
--cc=tianx@yunsilicon.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