All of lore.kernel.org
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Zong Li" <zong.li@sifive.com>
Cc: linux-perf-users@vger.kernel.org
Subject: Re: [PATCH v15 1/2] drivers/perf: riscv-iommu: add risc-v iommu pmu driver
Date: Fri, 02 Oct 2026 09:14:33 +0000	[thread overview]
Message-ID: <20261002091434.1A32D1F000FF@smtp.kernel.org> (raw)
In-Reply-To: <20261002063315.1535817-2-zong.li@sifive.com>

Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [High] perf/riscv: Torn read race between PMU read and IRQ handler corrupts event count
- [Medium] perf/riscv: UAF in CPU hotplug callback during PMU probe error path
--

commit 472769839e43688676e3929143858e4d52f609c7
Author: Zong Li <zong.li@sifive.com>

    drivers/perf: riscv-iommu: add risc-v iommu pmu driver

This commit introduces a new driver for the RISC-V IOMMU PMU, created as an
auxiliary device by the parent RISC-V IOMMU driver. The PMU provides event
and cycle counters with filtering support to collect performance metrics.

Link: https://lore.kernel.org/linux-riscv/20260618143634.7f3dd6c5@pumpkin/

> diff --git a/drivers/perf/riscv_iommu_pmu.c b/drivers/perf/riscv_iommu_pmu.c
> index 0000000000000..25f217ac97e7f
> --- /dev/null
> +++ b/drivers/perf/riscv_iommu_pmu.c

[ ... ]

> +static void riscv_iommu_pmu_set_period(struct perf_event *event)
> +{
> +	struct riscv_iommu_pmu *pmu = to_riscv_iommu_pmu(event->pmu);
> +	struct hw_perf_event *hwc = &event->hw;
> +	u64 counter_mask = pmu->cntr_mask[hwc->idx];
> +	u64 period;
> +
> +	/*
> +	 * Limit the maximum period to prevent the counter value
> +	 * from overtaking the one we are about to program.
> +	 * In effect we are reducing max_period to account for
> +	 * interrupt latency (and we are being very conservative).
> +	 */
> +	period = counter_mask >> 1;
> +	riscv_iommu_pmu_set_counter(pmu, hwc->idx, period);
> +	local64_set(&hwc->prev_count, period);
> +}

[ ... ]

> +static void riscv_iommu_pmu_update(struct perf_event *event)
> +{
> +	struct hw_perf_event *hwc = &event->hw;
> +	struct riscv_iommu_pmu *pmu = to_riscv_iommu_pmu(event->pmu);
> +	u64 delta, prev, now;
> +	u32 idx = hwc->idx;
> +	u64 counter_mask = pmu->cntr_mask[idx];
> +
> +	/*
> +	 * riscv_iommu_pmu_set_period() resets the hardware counter and
> +	 * prev_count as two separate writes.
> +	 * Pairing a "prev" read from before that reset with a "now" read from
> +	 * after it would produce a nonsensical, possibly huge, delta.
> +	 * Re-checking prev_count after the hardware read detects that torn
> +	 * pairing and retries.
> +	 */
> +	do {
> +		prev = local64_read(&hwc->prev_count);
> +		now = riscv_iommu_pmu_get_counter(pmu, idx);
> +	} while (prev != local64_read(&hwc->prev_count) ||
> +		 local64_cmpxchg(&hwc->prev_count, prev, now) != prev);
> +
> +	delta = (now - prev) & counter_mask;
> +	local64_add(delta, &event->count);
> +}

[ ... ]

> +static void riscv_iommu_pmu_read(struct perf_event *event)
> +{
> +	riscv_iommu_pmu_update(event);
> +}

[Severity: High]
Does this code allow a lockless read to calculate a torn update delta?

The commit message notes that IRQCHIP_MOVE_DEFERRED can cause the PMU interrupt
to be routed to a different CPU than the event is bound to.

If riscv_iommu_pmu_read() is called locklessly on CPU B, it can race with
riscv_iommu_pmu_irq_handler() running on CPU A. In riscv_iommu_pmu_set_period(),
the hardware counter is written before the shadow copy prev_count.

If CPU B reads the old near-overflow prev_count, and then CPU A resets the
hardware counter, CPU B could read the new reset hardware counter. Because
CPU A hasn't reset the software prev_count yet, CPU B's loop validation
(prev == local64_read()) would succeed, producing a massive wrap-around spike
in the event count.

[ ... ]

> +static int riscv_iommu_pmu_probe(struct auxiliary_device *auxdev,
> +				 const struct auxiliary_device_id *id)
> +{

[ ... ]

> +	ret = devm_add_action_or_reset(&auxdev->dev,
> +				       riscv_iommu_pmu_do_unregister,
> +				       iommu_pmu);
> +	if (ret) {
> +		/*
> +		 * The action above has already run, so the pmu is unregistered
> +		 * and pmu->cpu_pmu_context is freed. Drop the cpuhp instance
> +		 * with _nocalls() so the teardown callback cannot reach it, and
> +		 * so it does not outlive iommu_pmu on the global cpuhp list.
> +		 */
> +		cpuhp_state_remove_instance_nocalls(cpuhp_state, &iommu_pmu->node);
> +		return ret;
> +	}

[Severity: Medium]
Can this sequence result in a use-after-free during a concurrent CPU offline
event?

If devm_add_action_or_reset() fails to allocate a devres node, it will
immediately execute riscv_iommu_pmu_do_unregister(), which calls
perf_pmu_unregister() and frees the PMU per-CPU contexts.

Because the CPU hotplug instance is not removed before the teardown action
executes, a concurrent CPU hotplug callback (riscv_iommu_pmu_offline_cpu)
might be invoked in this window. Could this cause perf_pmu_migrate_context()
to be called on the already-freed contexts?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20261002063315.1535817-1-zong.li@sifive.com?part=1

  reply	other threads:[~2026-10-02  9:14 UTC|newest]

Thread overview: 10+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-02  6:33 [PATCH v15 0/2] RISC-V IOMMU HPM support Zong Li
2026-10-02  6:33 ` Zong Li
2026-10-02  6:33 ` [PATCH v15 1/2] drivers/perf: riscv-iommu: add risc-v iommu pmu driver Zong Li
2026-10-02  6:33   ` Zong Li
2026-10-02  9:14   ` sashiko-bot [this message]
2026-10-02  6:33 ` [PATCH v15 2/2] iommu/riscv: create a auxiliary device for HPM Zong Li
2026-10-02  6:33   ` Zong Li
2026-10-02  9:14   ` sashiko-bot
2026-10-09  8:49   ` Jörg Rödel
2026-10-09  8:49     ` Jörg Rödel

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=20261002091434.1A32D1F000FF@smtp.kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=linux-perf-users@vger.kernel.org \
    --cc=sashiko-reviews@lists.linux.dev \
    --cc=zong.li@sifive.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.