Kernel KVM virtualization development
 help / color / mirror / Atom feed
From: Sean Christopherson <seanjc@google.com>
To: sashiko-reviews@lists.linux.dev
Cc: Yosry Ahmed <yosry@kernel.org>, kvm@vger.kernel.org
Subject: Re: [PATCH v7 08/17] KVM: x86/pmu: Check mediated PMU counter enablement before event filters
Date: Fri, 29 May 2026 17:35:00 -0700	[thread overview]
Message-ID: <ahowtCCtnr9t5DGy@google.com> (raw)
In-Reply-To: <20260528005419.0228F1F00A3A@smtp.kernel.org>

On Thu, May 28, 2026, sashiko-bot@kernel.org wrote:
> Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
> 
> Pre-existing issues:
> - [High] Guest can bypass PMU event filters for fixed counters by modifying MSR_CORE_PERF_FIXED_CTR_CTRL.
> --
> 
> commit 270fc772a7eb457f31ead154a0c426817961ae8a
> Author: Yosry Ahmed <yosry@kernel.org>
> 
> KVM: x86/pmu: Check mediated PMU counter enablement before event filters
> 
> This commit checks if a PMU counter is enabled by the guest before performing
> the potentially expensive PMU event filter lookup. It modifies
> kvm_mediated_pmu_refresh_event_filter to use pmc_is_locally_enabled.
> 
> > diff --git a/arch/x86/kvm/pmu.c b/arch/x86/kvm/pmu.c
> > index afbc731e72174..67dbbd4c73036 100644
> > --- a/arch/x86/kvm/pmu.c
> > +++ b/arch/x86/kvm/pmu.c
> > @@ -532,7 +532,7 @@ static bool pmc_is_event_allowed(struct kvm_pmc *pmc)
> >  
> >  static void kvm_mediated_pmu_refresh_event_filter(struct kvm_pmc *pmc)
> >  {
> > -	bool allowed = pmc_is_event_allowed(pmc);
> > +	bool allowed = pmc_is_locally_enabled(pmc) && pmc_is_event_allowed(pmc);
> 
> [Severity: High]
> This is a pre-existing issue, but was it intended for guests to be able to
> bypass PMU event filters for fixed counters by writing to the MSR twice?
> 
> Looking at reprogram_fixed_counters() in arch/x86/kvm/vmx/pmu_intel.c,
> pmu->fixed_ctr_ctrl_hw is unconditionally overwritten with raw guest data
> before checking which counters changed:
> 
> arch/x86/kvm/vmx/pmu_intel.c:reprogram_fixed_counters() {
>     ...
> 	pmu->fixed_ctr_ctrl = data;
> 	pmu->fixed_ctr_ctrl_hw = data;
> 	for (i = 0; i < pmu->nr_arch_fixed_counters; i++) {
> 		u8 new_ctrl = fixed_ctrl_field(data, i);
> 		u8 old_ctrl = fixed_ctrl_field(old_fixed_ctr_ctrl, i);
> 
> 		if (old_ctrl == new_ctrl)
> 			continue;
>     ...
> 		kvm_pmu_request_counter_reprogram(pmc);
> 	}
> }
> 
> Because kvm_pmu_request_counter_reprogram() is skipped when the counter's
> control bits haven't changed, kvm_mediated_pmu_refresh_event_filter() is
> never called to apply the filter mask.
> 
> Could a guest enable a rejected counter (which gets correctly filtered and
> cleared in fixed_ctr_ctrl_hw by the first write), and then write the MSR a
> second time to enable a different counter while leaving the rejected
> counter's bits set?
> 
> The second write would inject the unfiltered enable bits into
> fixed_ctr_ctrl_hw, and since the software state (old_ctrl == new_ctrl)
> matches, KVM skips reprogramming it. Does this allow the rejected counter to
> remain enabled in hardware upon the next VM-enter, completely bypassing the
> event filters?

Hrm, does look like that's the case.  If the guest toggles a different PMC, KVM
will update pmu->fixed_ctr_ctrl_hw and reprogram the PMC that is changing, but
not the others that are enabled in pmu->fixed_ctr_ctrl_hw.

Aha!  I think this is quite easy to fix: use fixed_ctr_ctrl_hw as the basis for
the diff.  For the perf-based PMU, fixed_ctr_ctrl_hw == fixed_ctr_ctrl at all
times.  For the mediated PMU, "reprogramming" means changes the values that are
loaded into hardware, and so unless I'm missing something, this?  I'll test and
send a patch next week.

idiff --git arch/x86/kvm/vmx/pmu_intel.c arch/x86/kvm/vmx/pmu_intel.c
index 453cb3d3ec9b..a73a9515d96c 100644
--- arch/x86/kvm/vmx/pmu_intel.c
+++ arch/x86/kvm/vmx/pmu_intel.c
@@ -56,8 +56,16 @@ static struct x86_pmu_lbr *vcpu_to_lbr_records(struct kvm_vcpu *vcpu)
 
 static void reprogram_fixed_counters(struct kvm_pmu *pmu, u64 data)
 {
+       /*
+        * Compare against the value the mediated PMU shoves into hardware, not
+        * the guest's desired value.  For the emulated PMU (proxied via perf),
+        * they are one and the same (fixed_ctr_ctrl_hw isn't used other than
+        * here).  For the mediated PMU, KVM needs to reprogram the actual MSR,
+        * and so needs to react to potential changes in the value shoved into
+        * hardware, e.g. to ensure the event filter is enforced.
+        */
+       u64 old_fixed_ctr_ctrl = pmu->fixed_ctr_ctrl_hw;
        struct kvm_pmc *pmc;
-       u64 old_fixed_ctr_ctrl = pmu->fixed_ctr_ctrl;
        int i;
 
        pmu->fixed_ctr_ctrl = data;


Note, general purpose counters (thankfully) don't have the same bug.

			if (data != pmc->eventsel) {
				pmc->eventsel = data;
				pmc->eventsel_hw = data;
				kvm_pmu_request_counter_reprogram(pmc);
			}

Oh, and for posterity, using fixed_ctr_ctrl_hw won't mess up pmc_in_use, because
it's unused by the mediated PMU.  It's purpose is solely for releasing perf events
that are no longer being actively used.  It's a bit hard to see, but need_cleanup
will never be set for the mediated PMU, because pmu->event_count will always be
zero.

	if (vcpu->scheduled_out && pmu->version && pmu->event_count) {
		pmu->need_cleanup = true;
		kvm_make_request(KVM_REQ_PMU, vcpu);
	}

To make that more obvious, I think it makes sense to add

  static inline void __kvm_pmu_mark_pmc_in_use(struct kvm_vcpu *vcpu, u8 idx)
 {
	if (kvm_vcpu_has_mediated_pmu(vcpu))
		return;

	__set_bit(idx, vcpu_to_pmu(vcpu)->pmc_in_use);
  }

and then use that everywhere, and WARN if kvm_pmu_cleanup() is ever called with
a mediated PMU.

  reply	other threads:[~2026-05-30  0:35 UTC|newest]

Thread overview: 37+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-05-27 23:46 [PATCH v7 00/17] KVM: x86/pmu: Add support for AMD Host-Only/Guest-Only bits Yosry Ahmed
2026-05-27 23:46 ` [PATCH v7 01/17] KVM: nSVM: Stop leaking single-stepping on VMRUN into L2 Yosry Ahmed
2026-05-27 23:46 ` [PATCH v7 02/17] KVM: nSVM: Bail early out of VMRUN emulation if advancing RIP fails Yosry Ahmed
2026-05-27 23:46 ` [PATCH v7 03/17] KVM: nSVM: Unify RIP and PMU handling calls when emulating VMRUN Yosry Ahmed
2026-05-27 23:46 ` [PATCH v7 04/17] KVM: nSVM: Move VMRUN instruction retirement after entering guest mode Yosry Ahmed
2026-05-27 23:46 ` [PATCH v7 05/17] KVM: x86: Move enable_pmu/enable_mediated_pmu to pmu.h and pmu.c Yosry Ahmed
2026-05-27 23:47 ` [PATCH v7 06/17] KVM: x86/pmu: Rename reprogram_counters() to clarify usage Yosry Ahmed
2026-05-27 23:47 ` [PATCH v7 07/17] KVM: x86/pmu: Do a single atomic OR when reprogramming counters Yosry Ahmed
2026-05-27 23:47 ` [PATCH v7 08/17] KVM: x86/pmu: Check mediated PMU counter enablement before event filters Yosry Ahmed
2026-05-28  0:54   ` sashiko-bot
2026-05-30  0:35     ` Sean Christopherson [this message]
2026-05-27 23:47 ` [PATCH v7 09/17] KVM: x86/pmu: Add support for KVM_X86_PMU_OP_OPTIONAL_RET0 Yosry Ahmed
2026-05-27 23:47 ` [PATCH v7 10/17] KVM: x86/pmu: Disable counters based on Host-Only/Guest-Only bits in SVM Yosry Ahmed
2026-05-28  0:34   ` sashiko-bot
2026-05-28  1:43     ` Sean Christopherson
2026-05-27 23:47 ` [PATCH v7 11/17] KVM: x86/pmu: Track mediated PMU counters with mode-specific enables Yosry Ahmed
2026-05-28  0:45   ` sashiko-bot
2026-05-27 23:47 ` [PATCH v7 12/17] KVM: x86/pmu: Reprogram Host/Guest-Only counters on nested transitions Yosry Ahmed
2026-05-27 23:47 ` [PATCH v7 13/17] KVM: x86/pmu: Allow Host-Only/Guest-Only bits with nSVM and mediated PMU Yosry Ahmed
2026-05-27 23:47 ` [PATCH v7 14/17] KVM: selftests: Refactor allocating guest stack into a helper Yosry Ahmed
2026-05-27 23:47 ` [PATCH v7 15/17] KVM: selftests: Allocate a dedicated guest page for x86 L2 guest stack Yosry Ahmed
2026-05-28  2:56   ` Sean Christopherson
2026-05-28 17:58     ` Yosry Ahmed
2026-05-28 18:01       ` Sean Christopherson
2026-05-28 18:03         ` Yosry Ahmed
2026-05-27 23:47 ` [PATCH v7 16/17] KVM: selftests: Drop L1-provided stacks for L2 guests on x86 Yosry Ahmed
2026-05-27 23:47 ` [PATCH v7 17/17] KVM: selftests: Add svm_pmu_host_guest_test for Host-Only/Guest-Only bits Yosry Ahmed
2026-05-28  2:25   ` Sean Christopherson
2026-05-28 18:01     ` Yosry Ahmed
2026-05-28 18:04       ` Sean Christopherson
2026-05-28 18:15         ` Jim Mattson
2026-05-28  2:27 ` [PATCH v7 00/17] KVM: x86/pmu: Add support for AMD " Sean Christopherson
2026-05-28 18:02   ` Yosry Ahmed
2026-05-28 18:05     ` Sean Christopherson
2026-05-28  8:30 ` Mi, Dapeng
2026-05-28 18:01   ` Yosry Ahmed
2026-05-29 22:47 ` Sean Christopherson

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=ahowtCCtnr9t5DGy@google.com \
    --to=seanjc@google.com \
    --cc=kvm@vger.kernel.org \
    --cc=sashiko-reviews@lists.linux.dev \
    --cc=yosry@kernel.org \
    /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