From: sashiko-bot@kernel.org
To: "Colton Lewis" <coltonlewis@google.com>
Cc: "Oliver Upton" <oupton@kernel.org>,
"Marc Zyngier" <maz@kernel.org>,
linux-perf-users@vger.kernel.org, kvmarm@lists.linux.dev,
kvm@vger.kernel.org
Subject: Re: [PATCH 11/21] KVM: arm64: Context swap Partitioned PMU guest registers
Date: Fri, 12 Jun 2026 19:51:11 +0000 [thread overview]
Message-ID: <20260612195112.098F21F000E9@smtp.kernel.org> (raw)
In-Reply-To: <20260612192909.1153907-12-coltonlewis@google.com>
Thank you for your contribution! Sashiko AI review found 5 potential issue(s) to consider:
- [High] TOCTOU race in `kvm_pmu_put()` leads to lost hardware overflows and inconsistent counter values.
- [High] `kvm_pmu_put()` clobbers the guest's virtual `PMCR_EL0` with host physical read-only fields.
- [High] Out-of-bounds bit shift and undefined behavior in `GENMASK_ULL` for `kvm_pmu_host_counter_mask()`.
- [High] Missing mandatory `isb()` after writing control-plane PMU registers in `kvm_pmu_put()`.
- [High] Guest accesses to the trapped `PMOVSSET_EL0` register return stale data, causing the guest to permanently miss PMU overflows.
--
commit 1e067bf0381df5bfe1db83a20f08aa650fd65999
Author: Colton Lewis <coltonlewis@google.com>
KVM: arm64: Context swap Partitioned PMU guest registers
This commit saves and restores untrapped PMU registers when the PMU is
partitioned, bypassing the context swap for emulated vPMUs. It also clears
PMOVS guest hardware counters to avoid generating spurious interrupts.
> diff --git a/arch/arm64/kvm/pmu-direct.c b/arch/arm64/kvm/pmu-direct.c
> index 43f04c2f33d44..79022447cfb9a 100644
> --- a/arch/arm64/kvm/pmu-direct.c
> +++ b/arch/arm64/kvm/pmu-direct.c
[ ... ]
> +u64 kvm_pmu_host_counter_mask(struct arm_pmu *pmu)
> +{
> + u8 nr_counters = *host_data_ptr(nr_event_counters);
> +
> + if (pmu_is_partitioned(pmu))
> + return GENMASK_ULL(nr_counters - 1, pmu->max_guest_counters);
[Severity: High]
Does this code trigger undefined behavior if the PMU implements zero event
counters or if the guest is configured to use all available counters?
If nr_counters == 0, nr_counters - 1 evaluates to -1, resulting in
GENMASK_ULL(-1, 0), which expands to a right shift by 64.
If max_guest_counters == nr_counters, the high bound is strictly less than
the low bound, violating the macro's constraints. Both cases require
explicit bounds checking.
> +
> + return ARMV8_PMU_CNT_MASK_ALL;
> +}
[ ... ]
> +void kvm_pmu_put(struct kvm_vcpu *vcpu)
> +{
[ ... ]
> + val = read_sysreg(pmselr_el0);
> + __vcpu_assign_sys_reg(vcpu, PMSELR_EL0, val);
> +
> + val = read_sysreg(pmcr_el0);
> + __vcpu_assign_sys_reg(vcpu, PMCR_EL0, val);
[Severity: High]
Can this clobber the guest's virtual PMCR_EL0 with host-specific read-only
fields?
By reading the raw hardware pmcr_el0 and directly assigning it to the vCPU
state, KVM overwrites the virtualized read-only fields (such as IMP, IDCODE,
and N) with the host's physical values.
This might serialize the leaked host topology when userspace reads the
register, causing migration issues if the VM is moved to a host with
different PMU capabilities.
> +
> + /* Mask these to only save the guest relevant bits. */
> + mask = kvm_pmu_guest_counter_mask(pmu);
[ ... ]
> + /* Save pending guest hardware overflows. */
> + local_irq_save(flags);
> + val = read_sysreg(pmovsset_el0);
> + __vcpu_rmw_sys_reg(vcpu, PMOVSSET_EL0, |=, val & mask);
> + write_sysreg(val & mask, pmovsclr_el0);
> + local_irq_restore(flags);
> +
> + /* Stop guest counters and disable interrupts in hardware. */
> + write_sysreg(mask, pmcntenclr_el0);
[Severity: High]
Does this create a race condition where hardware overflows can be
permanently lost?
The hardware counters are still running while kvm_pmu_put() reads their
state and the overflow register. A counter might overflow in the window
between reading pmovsset_el0 and stopping the counters with pmcntenclr_el0.
If the guest had disabled physical PMU interrupts for that counter, no IRQ
fires to rescue the overflow state. The overflow bit remains set in hardware
but is missed by KVM, and when the vCPU is scheduled back in, kvm_pmu_load()
will unconditionally clear pmovsclr_el0, destroying the unrecorded overflow.
Also, does this design lead to stale reads when the guest polls for
overflows?
Since the counters run directly in hardware without syncing back to memory
until vcpu_put, if a guest traps to pmu_reg_read() in
arch/arm64/kvm/sys_regs.c to read PMOVSSET_EL0:
pmu_reg_read()
case PMOVSSET_EL0:
val = __vcpu_sys_reg(vcpu, reg);
break;
It will receive the stale in-memory value instead of seeing the active
hardware overflow accumulating in the physical register.
> + write_sysreg(mask, pmintenclr_el1);
> +
> + kvm_pmu_set_guest_counters(pmu, 0);
> + preempt_enable();
> +}
[Severity: High]
Are we missing a mandatory Context Synchronization Event here?
After writing to control-plane registers like pmcntenclr_el0 and
pmintenclr_el1, an isb() must follow to ensure the CPU pipeline
resolves the new configuration.
Without the barrier, the CPU could continue executing the host kernel using
a stale configuration, potentially allowing hardware counters to run and
deliver spurious physical PMU interrupts during host execution.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260612192909.1153907-1-coltonlewis@google.com?part=11
next prev parent reply other threads:[~2026-06-12 19:51 UTC|newest]
Thread overview: 35+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-06-12 19:28 [PATCH v8 00/21] ARM64 PMU Partitioning Colton Lewis
2026-06-12 19:28 ` [PATCH 01/21] arm64: cpufeature: Add cpucap for HPMN0 Colton Lewis
2026-06-12 19:28 ` [PATCH 02/21] KVM: arm64: Reorganize PMU includes Colton Lewis
2026-06-12 19:28 ` [PATCH 03/21] KVM: arm64: Reorganize PMU functions Colton Lewis
2026-06-12 19:56 ` sashiko-bot
2026-06-12 19:28 ` [PATCH 04/21] perf: arm_pmuv3: Generalize counter bitmasks Colton Lewis
2026-06-12 19:28 ` [PATCH 05/21] perf: arm_pmuv3: Check cntr_mask before using pmccntr Colton Lewis
2026-06-12 19:42 ` sashiko-bot
2026-06-12 19:28 ` [PATCH 06/21] perf: arm_pmuv3: Allocate counter indices from high to low Colton Lewis
2026-06-12 19:28 ` [PATCH 07/21] perf: arm_pmuv3: Add method to partition the PMU Colton Lewis
2026-06-12 19:28 ` [PATCH 08/21] KVM: arm64: Set up FGT for Partitioned PMU Colton Lewis
2026-06-12 19:45 ` sashiko-bot
2026-06-12 19:28 ` [PATCH 09/21] KVM: arm64: Add Partitioned PMU register trap handlers Colton Lewis
2026-06-12 19:51 ` sashiko-bot
2026-06-12 19:28 ` [PATCH 10/21] KVM: arm64: Set up MDCR_EL2 to handle a Partitioned PMU Colton Lewis
2026-06-12 19:52 ` sashiko-bot
2026-06-12 19:28 ` [PATCH 11/21] KVM: arm64: Context swap Partitioned PMU guest registers Colton Lewis
2026-06-12 19:51 ` sashiko-bot [this message]
2026-06-12 19:29 ` [PATCH 12/21] KVM: arm64: Enforce PMU event filter at vcpu_load() Colton Lewis
2026-06-12 19:53 ` sashiko-bot
2026-06-12 19:29 ` [PATCH 13/21] perf: Add perf_pmu_resched_update() Colton Lewis
2026-06-12 19:29 ` [PATCH 14/21] KVM: arm64: Apply dynamic guest counter reservations Colton Lewis
2026-06-12 19:50 ` sashiko-bot
2026-06-12 19:29 ` [PATCH 15/21] KVM: arm64: Implement lazy PMU context swaps Colton Lewis
2026-06-12 19:50 ` sashiko-bot
2026-06-12 19:29 ` [PATCH 16/21] perf: arm_pmuv3: Handle IRQs for Partitioned PMU guest counters Colton Lewis
2026-06-12 19:57 ` sashiko-bot
2026-06-12 19:29 ` [PATCH 17/21] KVM: arm64: Detect overflows for the Partitioned PMU Colton Lewis
2026-06-12 19:58 ` sashiko-bot
2026-06-12 19:29 ` [PATCH 18/21] KVM: arm64: Add vCPU device attr to partition the PMU Colton Lewis
2026-06-12 19:54 ` sashiko-bot
2026-06-12 19:29 ` [PATCH 19/21] KVM: selftests: Add find_bit to KVM library Colton Lewis
2026-06-12 20:01 ` sashiko-bot
2026-06-12 19:29 ` [PATCH 20/21] KVM: arm64: selftests: Add test case for Partitioned PMU Colton Lewis
2026-06-12 19:29 ` [PATCH 21/21] KVM: arm64: selftests: Relax testing for exceptions when partitioned Colton Lewis
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=20260612195112.098F21F000E9@smtp.kernel.org \
--to=sashiko-bot@kernel.org \
--cc=coltonlewis@google.com \
--cc=kvm@vger.kernel.org \
--cc=kvmarm@lists.linux.dev \
--cc=linux-perf-users@vger.kernel.org \
--cc=maz@kernel.org \
--cc=oupton@kernel.org \
--cc=sashiko-reviews@lists.linux.dev \
/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