* [PATCH 1/4] KVM: SVM: Always update LBR MSR intercepts on full MSR intercept recalc
[not found] <20261020234535.3182385-1-jmattson@google.com>
@ 2026-10-20 23:45 ` Jim Mattson
2026-10-21 0:09 ` Yosry Ahmed
2026-10-20 23:45 ` [PATCH 2/4] KVM: VMX: Refresh " Jim Mattson
1 sibling, 1 reply; 8+ messages in thread
From: Jim Mattson @ 2026-10-20 23:45 UTC (permalink / raw)
To: Sean Christopherson, Paolo Bonzini
Cc: Jim Mattson, kvm, linux-kernel, Yosry Ahmed, Like Xu, stable
Split the "already up-to-date" check out of the code that writes the LBR
MSR intercepts, and write the intercepts unconditionally from
svm_recalc_msr_intercepts(), so that changes to userspace MSR filters are
reflected in the MSR permissions map.
svm_recalc_msr_intercepts() is invoked in response to
KVM_REQ_RECALC_INTERCEPTS, which is raised on MSR filter updates. But
svm->lbr_msrs_intercepted tracks only the interception KVM wants, not
what is actually in the bitmap after the filter is applied. If the LBR
MSRs are passed through when userspace installs a filter that denies
them, the early return leaves them passed through, and the guest can
access them without exiting to userspace. Conversely, if a filter
forced interception when LBR virtualization was enabled, relaxing the
filter leaves the MSRs needlessly intercepted. Either way, the bitmap
remains stale until the next change to LBR_CTL.
Full intercept recalculations are rare (e.g. on RESET/INIT, EFER.SVME
toggles, and CPUID, PERF_CAPABILITIES, and MSR filter updates), and
never happen on nested VMRUN or #VMEXIT, so writing the intercepts there
does not reintroduce the redundant per-VMRUN bitmap updates that the
check was added to avoid. And because svm_recalc_msr_intercepts()
already unconditionally writes the intercepts for many other MSRs (and
thus marks Hyper-V's nested enlightenments dirty), writing the LBR MSR
intercepts there doesn't introduce any new invalidations.
Add a comment to clarify that lbr_msrs_intercepted reflects KVM's
desired interception, not necessarily the state of the bitmap.
Fixes: 3fa05f96fc08 ("KVM: SVM: Fix redundant updates of LBR MSR intercepts")
Cc: stable@vger.kernel.org
Signed-off-by: Jim Mattson <jmattson@google.com>
---
arch/x86/kvm/svm/svm.c | 28 +++++++++++++++++++++++-----
arch/x86/kvm/svm/svm.h | 6 ++++++
2 files changed, 29 insertions(+), 5 deletions(-)
diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c
index fe0cba4731b2..55b3ee840365 100644
--- a/arch/x86/kvm/svm/svm.c
+++ b/arch/x86/kvm/svm/svm.c
@@ -721,14 +721,11 @@ void *svm_alloc_permissions_map(unsigned long size, gfp_t gfp_mask)
return pm;
}
-static void svm_recalc_lbr_msr_intercepts(struct kvm_vcpu *vcpu)
+static void svm_set_lbr_msr_intercepts(struct kvm_vcpu *vcpu)
{
struct vcpu_svm *svm = to_svm(vcpu);
bool intercept = !(svm->vmcb->control.misc_ctl2 & SVM_MISC2_ENABLE_V_LBR);
- if (intercept == svm->lbr_msrs_intercepted)
- return;
-
svm_set_intercept_for_msr(vcpu, MSR_IA32_LASTBRANCHFROMIP, MSR_TYPE_RW, intercept);
svm_set_intercept_for_msr(vcpu, MSR_IA32_LASTBRANCHTOIP, MSR_TYPE_RW, intercept);
svm_set_intercept_for_msr(vcpu, MSR_IA32_LASTINTFROMIP, MSR_TYPE_RW, intercept);
@@ -740,6 +737,22 @@ static void svm_recalc_lbr_msr_intercepts(struct kvm_vcpu *vcpu)
svm->lbr_msrs_intercepted = intercept;
}
+static void svm_recalc_lbr_msr_intercepts(struct kvm_vcpu *vcpu)
+{
+ struct vcpu_svm *svm = to_svm(vcpu);
+ bool intercept = !(svm->vmcb->control.misc_ctl2 & SVM_MISC2_ENABLE_V_LBR);
+
+ /*
+ * Skip redundant updates from svm_update_lbrv(), e.g. on every nested
+ * VMRUN and #VMEXIT. Note, svm_recalc_msr_intercepts() updates the
+ * bitmap unconditionally, as userspace MSR filters may have changed.
+ */
+ if (intercept == svm->lbr_msrs_intercepted)
+ return;
+
+ svm_set_lbr_msr_intercepts(vcpu);
+}
+
void svm_vcpu_free_msrpm(void *msrpm)
{
__free_pages(virt_to_page(msrpm), get_order(MSRPM_SIZE));
@@ -795,8 +808,13 @@ static void svm_recalc_msr_intercepts(struct kvm_vcpu *vcpu)
svm_disable_intercept_for_msr(vcpu, MSR_SYSCALL_MASK, MSR_TYPE_RW);
#endif
+ /*
+ * Unconditionally refresh the LBR MSR intercepts, as userspace MSR
+ * filters may have changed, in which case the bitmap may be stale even
+ * if KVM's desired interception hasn't changed.
+ */
if (lbrv)
- svm_recalc_lbr_msr_intercepts(vcpu);
+ svm_set_lbr_msr_intercepts(vcpu);
if (cpu_feature_enabled(X86_FEATURE_IBPB))
svm_set_intercept_for_msr(vcpu, MSR_IA32_PRED_CMD, MSR_TYPE_W,
diff --git a/arch/x86/kvm/svm/svm.h b/arch/x86/kvm/svm/svm.h
index 84f19026d3e8..62e08d6d4706 100644
--- a/arch/x86/kvm/svm/svm.h
+++ b/arch/x86/kvm/svm/svm.h
@@ -364,6 +364,12 @@ struct vcpu_svm {
bool avic_irq_window;
bool x2avic_msrs_intercepted;
+
+ /*
+ * True if KVM wants the LBR MSRs to be intercepted. Note, userspace MSR
+ * filters may force interception regardless, i.e. this doesn't
+ * necessarily reflect the state of the MSR bitmap.
+ */
bool lbr_msrs_intercepted;
/* Guest GIF value, used when vGIF is not enabled */
--
2.56.0.212.g129ede20d9-goog
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH 2/4] KVM: VMX: Refresh LBR MSR intercepts on full MSR intercept recalc
[not found] <20261020234535.3182385-1-jmattson@google.com>
2026-10-20 23:45 ` [PATCH 1/4] KVM: SVM: Always update LBR MSR intercepts on full MSR intercept recalc Jim Mattson
@ 2026-10-20 23:45 ` Jim Mattson
2026-11-04 20:45 ` Sean Christopherson
1 sibling, 1 reply; 8+ messages in thread
From: Jim Mattson @ 2026-10-20 23:45 UTC (permalink / raw)
To: Sean Christopherson, Paolo Bonzini
Cc: Jim Mattson, kvm, linux-kernel, Yosry Ahmed, Like Xu, stable
Re-apply the LBR MSR intercepts in vmx_recalc_msr_intercepts() if the
LBRs are currently passed through, so that changes to userspace MSR
filters are reflected in the MSR bitmap. Unlike SVM, which can simply
rewrite the intercepts in either direction, leave the bitmap alone if
the LBRs aren't passed through, as a filter can only force interception,
never prevent it, i.e. the bitmap is already correct. Note, clearing
msr_passthrough to force vmx_passthrough_lbr_msrs() to re-apply the
intercepts on the next VM-Enter isn't an option, as doing so would
leave stale passthrough bits behind if the guest LBR event is no longer
active.
vmx_recalc_msr_intercepts() is invoked in response to
KVM_REQ_RECALC_INTERCEPTS, which is raised on MSR filter updates, but it
skips the LBR MSRs, and vmx_enable_lbr_msrs_passthrough() does nothing
if lbr_desc->msr_passthrough is already set. If the LBR MSRs are passed
through when userspace installs a filter that denies them, they remain
passed through, and the guest can access them without exiting to
userspace. Conversely, if a filter forced interception when the guest
LBR event became active, relaxing the filter leaves the MSRs needlessly
intercepted. Either way, the bitmap remains stale until the guest LBR
event is torn down and recreated.
Only x2APIC MSRs are exempt from userspace filtering (see
kvm_msr_allowed() and the KVM_X86_SET_MSR_FILTER documentation), and the
filter is honored when LBR passthrough is first enabled, so KVM's
behavior shouldn't depend on whether the filter is set before or after
the guest enables LBRs. Drop the LBR MSRs from the comment claiming
that they can't be filtered by userspace, and clarify that
lbr_desc.msr_passthrough tracks KVM's desired interception, which may
not match the MSR bitmap when userspace filters are in play.
Fixes: 9254beaafd12 ("KVM: vmx/pmu: Reduce the overhead of LBR pass-through or cancellation")
Cc: stable@vger.kernel.org
Signed-off-by: Jim Mattson <jmattson@google.com>
---
arch/x86/kvm/vmx/pmu_intel.c | 20 +++++++++++++++++++-
arch/x86/kvm/vmx/pmu_intel.h | 7 ++++++-
arch/x86/kvm/vmx/vmx.c | 6 ++++--
arch/x86/kvm/vmx/vmx.h | 1 +
4 files changed, 30 insertions(+), 4 deletions(-)
diff --git a/arch/x86/kvm/vmx/pmu_intel.c b/arch/x86/kvm/vmx/pmu_intel.c
index 70a8c4816135..b945213f0b68 100644
--- a/arch/x86/kvm/vmx/pmu_intel.c
+++ b/arch/x86/kvm/vmx/pmu_intel.c
@@ -517,7 +517,8 @@ static void intel_pmu_refresh(struct kvm_vcpu *vcpu)
memset(&lbr_desc->records, 0, sizeof(lbr_desc->records));
/*
- * Setting passthrough of LBR MSRs is done only in the VM-Entry loop,
+ * LBR MSRs are initially passed through only in the VM-Entry loop (a
+ * full MSR intercept recalc merely refreshes an existing passthrough),
* and PMU refresh is disallowed after the vCPU has run, i.e. this code
* should never be reached while KVM is passing through MSRs.
*/
@@ -704,6 +705,23 @@ static inline void vmx_enable_lbr_msrs_passthrough(struct kvm_vcpu *vcpu)
lbr_desc->msr_passthrough = true;
}
+/*
+ * Refresh the LBR MSR intercepts if the LBRs are passed through, so that
+ * changes to userspace MSR filters are reflected in the MSR bitmap. There's
+ * nothing to do if the LBRs are intercepted, as a filter can only force
+ * interception, never prevent it.
+ */
+void vmx_recalc_lbr_msr_intercepts(struct kvm_vcpu *vcpu)
+{
+ struct lbr_desc *lbr_desc = vcpu_to_lbr_desc(vcpu);
+
+ if (WARN_ON_ONCE(!lbr_desc))
+ return;
+
+ if (lbr_desc->msr_passthrough)
+ vmx_update_intercept_for_lbr_msrs(vcpu, false);
+}
+
/*
* Higher priority host perf events (e.g. cpu pinned) could reclaim the
* pmu resources (e.g. LBR) that were assigned to the guest. This is
diff --git a/arch/x86/kvm/vmx/pmu_intel.h b/arch/x86/kvm/vmx/pmu_intel.h
index 5d9357640aa1..b553f63e19a6 100644
--- a/arch/x86/kvm/vmx/pmu_intel.h
+++ b/arch/x86/kvm/vmx/pmu_intel.h
@@ -34,7 +34,12 @@ struct lbr_desc {
*/
struct perf_event *event;
- /* True if LBRs are marked as not intercepted in the MSR bitmap */
+ /*
+ * True if KVM wants the LBR MSRs to be passed through, i.e. not
+ * intercepted. Note, userspace MSR filters may force interception of
+ * some or all LBR MSRs regardless, i.e. this doesn't necessarily
+ * reflect the state of the MSR bitmap.
+ */
bool msr_passthrough;
};
diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c
index 612ab07d4100..1c190a6303a3 100644
--- a/arch/x86/kvm/vmx/vmx.c
+++ b/arch/x86/kvm/vmx/vmx.c
@@ -4347,11 +4347,13 @@ static void vmx_recalc_msr_intercepts(struct kvm_vcpu *vcpu)
vmx_set_intercept_for_msr(vcpu, MSR_IA32_S_CET, MSR_TYPE_RW, intercept);
}
+ vmx_recalc_lbr_msr_intercepts(vcpu);
+
vmx_recalc_pmu_msr_intercepts(vcpu);
/*
- * x2APIC and LBR MSR intercepts are modified on-demand and cannot be
- * filtered by userspace.
+ * x2APIC intercepts are modified on-demand and cannot be filtered by
+ * userspace.
*/
}
diff --git a/arch/x86/kvm/vmx/vmx.h b/arch/x86/kvm/vmx/vmx.h
index dc8517f15bc4..ec6104b66009 100644
--- a/arch/x86/kvm/vmx/vmx.h
+++ b/arch/x86/kvm/vmx/vmx.h
@@ -667,6 +667,7 @@ static __always_inline struct vcpu_vmx *to_vmx(struct kvm_vcpu *vcpu)
void intel_pmu_cross_mapped_check(struct kvm_pmu *pmu);
int intel_pmu_create_guest_lbr_event(struct kvm_vcpu *vcpu);
void vmx_passthrough_lbr_msrs(struct kvm_vcpu *vcpu);
+void vmx_recalc_lbr_msr_intercepts(struct kvm_vcpu *vcpu);
struct vmcs *alloc_vmcs_cpu(bool shadow, int cpu, gfp_t flags);
void free_vmcs(struct vmcs *vmcs);
--
2.56.0.212.g129ede20d9-goog
^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [PATCH 1/4] KVM: SVM: Always update LBR MSR intercepts on full MSR intercept recalc
2026-10-20 23:45 ` [PATCH 1/4] KVM: SVM: Always update LBR MSR intercepts on full MSR intercept recalc Jim Mattson
@ 2026-10-21 0:09 ` Yosry Ahmed
2026-11-04 20:55 ` Sean Christopherson
0 siblings, 1 reply; 8+ messages in thread
From: Yosry Ahmed @ 2026-10-21 0:09 UTC (permalink / raw)
To: Jim Mattson
Cc: Sean Christopherson, Paolo Bonzini, kvm, linux-kernel, Like Xu,
stable
On Tue, Oct 20, 2026 at 4:45 PM Jim Mattson <jmattson@google.com> wrote:
>
> Split the "already up-to-date" check out of the code that writes the LBR
> MSR intercepts, and write the intercepts unconditionally from
> svm_recalc_msr_intercepts(), so that changes to userspace MSR filters are
> reflected in the MSR permissions map.
>
> svm_recalc_msr_intercepts() is invoked in response to
> KVM_REQ_RECALC_INTERCEPTS, which is raised on MSR filter updates. But
> svm->lbr_msrs_intercepted tracks only the interception KVM wants, not
> what is actually in the bitmap after the filter is applied. If the LBR
> MSRs are passed through when userspace installs a filter that denies
> them, the early return leaves them passed through, and the guest can
> access them without exiting to userspace. Conversely, if a filter
> forced interception when LBR virtualization was enabled, relaxing the
> filter leaves the MSRs needlessly intercepted. Either way, the bitmap
> remains stale until the next change to LBR_CTL.
>
> Full intercept recalculations are rare (e.g. on RESET/INIT, EFER.SVME
> toggles, and CPUID, PERF_CAPABILITIES, and MSR filter updates), and
> never happen on nested VMRUN or #VMEXIT, so writing the intercepts there
> does not reintroduce the redundant per-VMRUN bitmap updates that the
> check was added to avoid. And because svm_recalc_msr_intercepts()
> already unconditionally writes the intercepts for many other MSRs (and
> thus marks Hyper-V's nested enlightenments dirty), writing the LBR MSR
> intercepts there doesn't introduce any new invalidations.
>
> Add a comment to clarify that lbr_msrs_intercepted reflects KVM's
> desired interception, not necessarily the state of the bitmap.
>
> Fixes: 3fa05f96fc08 ("KVM: SVM: Fix redundant updates of LBR MSR intercepts")
> Cc: stable@vger.kernel.org
> Signed-off-by: Jim Mattson <jmattson@google.com>
> ---
> arch/x86/kvm/svm/svm.c | 28 +++++++++++++++++++++++-----
> arch/x86/kvm/svm/svm.h | 6 ++++++
> 2 files changed, 29 insertions(+), 5 deletions(-)
>
> diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c
> index fe0cba4731b2..55b3ee840365 100644
> --- a/arch/x86/kvm/svm/svm.c
> +++ b/arch/x86/kvm/svm/svm.c
> @@ -721,14 +721,11 @@ void *svm_alloc_permissions_map(unsigned long size, gfp_t gfp_mask)
> return pm;
> }
>
> -static void svm_recalc_lbr_msr_intercepts(struct kvm_vcpu *vcpu)
> +static void svm_set_lbr_msr_intercepts(struct kvm_vcpu *vcpu)
> {
> struct vcpu_svm *svm = to_svm(vcpu);
> bool intercept = !(svm->vmcb->control.misc_ctl2 & SVM_MISC2_ENABLE_V_LBR);
>
> - if (intercept == svm->lbr_msrs_intercepted)
> - return;
> -
> svm_set_intercept_for_msr(vcpu, MSR_IA32_LASTBRANCHFROMIP, MSR_TYPE_RW, intercept);
> svm_set_intercept_for_msr(vcpu, MSR_IA32_LASTBRANCHTOIP, MSR_TYPE_RW, intercept);
> svm_set_intercept_for_msr(vcpu, MSR_IA32_LASTINTFROMIP, MSR_TYPE_RW, intercept);
> @@ -740,6 +737,22 @@ static void svm_recalc_lbr_msr_intercepts(struct kvm_vcpu *vcpu)
> svm->lbr_msrs_intercepted = intercept;
Hmm I was going to ask if we can set svm->lbr_msrs_intercepted based
on whether or not svm_set_intercept_for_msr() actually set the
intercept, so that it also captures intercepts due to MSR filtering. I
assume that we didn't do this because MSR filters can result in
different interception status for different LBR MSRs, and we don't
want to track them individually?
Hmm even if we do track them individually (e.g. as a bitmap), it would
add a bit of complexity here because we'll need to plumb that into
svm_set_intercept_for_msr(), right?
I suppose if we go with "lbr_msrs_intercepted just means KVM wants to
intercept", then we should probably rename it accordingly?
> }
>
> +static void svm_recalc_lbr_msr_intercepts(struct kvm_vcpu *vcpu)
> +{
> + struct vcpu_svm *svm = to_svm(vcpu);
> + bool intercept = !(svm->vmcb->control.misc_ctl2 & SVM_MISC2_ENABLE_V_LBR);
> +
> + /*
> + * Skip redundant updates from svm_update_lbrv(), e.g. on every nested
> + * VMRUN and #VMEXIT. Note, svm_recalc_msr_intercepts() updates the
> + * bitmap unconditionally, as userspace MSR filters may have changed.
> + */
> + if (intercept == svm->lbr_msrs_intercepted)
> + return;
> +
> + svm_set_lbr_msr_intercepts(vcpu);
> +}
> +
> void svm_vcpu_free_msrpm(void *msrpm)
> {
> __free_pages(virt_to_page(msrpm), get_order(MSRPM_SIZE));
> @@ -795,8 +808,13 @@ static void svm_recalc_msr_intercepts(struct kvm_vcpu *vcpu)
> svm_disable_intercept_for_msr(vcpu, MSR_SYSCALL_MASK, MSR_TYPE_RW);
> #endif
>
> + /*
> + * Unconditionally refresh the LBR MSR intercepts, as userspace MSR
> + * filters may have changed, in which case the bitmap may be stale even
> + * if KVM's desired interception hasn't changed.
> + */
> if (lbrv)
> - svm_recalc_lbr_msr_intercepts(vcpu);
> + svm_set_lbr_msr_intercepts(vcpu);
>
> if (cpu_feature_enabled(X86_FEATURE_IBPB))
> svm_set_intercept_for_msr(vcpu, MSR_IA32_PRED_CMD, MSR_TYPE_W,
> diff --git a/arch/x86/kvm/svm/svm.h b/arch/x86/kvm/svm/svm.h
> index 84f19026d3e8..62e08d6d4706 100644
> --- a/arch/x86/kvm/svm/svm.h
> +++ b/arch/x86/kvm/svm/svm.h
> @@ -364,6 +364,12 @@ struct vcpu_svm {
>
> bool avic_irq_window;
> bool x2avic_msrs_intercepted;
> +
> + /*
> + * True if KVM wants the LBR MSRs to be intercepted. Note, userspace MSR
> + * filters may force interception regardless, i.e. this doesn't
> + * necessarily reflect the state of the MSR bitmap.
> + */
> bool lbr_msrs_intercepted;
>
> /* Guest GIF value, used when vGIF is not enabled */
> --
> 2.56.0.212.g129ede20d9-goog
>
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH 2/4] KVM: VMX: Refresh LBR MSR intercepts on full MSR intercept recalc
2026-10-20 23:45 ` [PATCH 2/4] KVM: VMX: Refresh " Jim Mattson
@ 2026-11-04 20:45 ` Sean Christopherson
2026-11-04 23:49 ` Jim Mattson
0 siblings, 1 reply; 8+ messages in thread
From: Sean Christopherson @ 2026-11-04 20:45 UTC (permalink / raw)
To: Jim Mattson
Cc: Paolo Bonzini, kvm, linux-kernel, Yosry Ahmed, Like Xu, stable
On Tue, Oct 20, 2026, Jim Mattson wrote:
> Re-apply the LBR MSR intercepts in vmx_recalc_msr_intercepts() if the
> LBRs are currently passed through, so that changes to userspace MSR
> filters are reflected in the MSR bitmap. Unlike SVM, which can simply
> rewrite the intercepts in either direction, leave the bitmap alone if
> the LBRs aren't passed through, as a filter can only force interception,
> never prevent it, i.e. the bitmap is already correct. Note, clearing
> msr_passthrough to force vmx_passthrough_lbr_msrs() to re-apply the
> intercepts on the next VM-Enter isn't an option, as doing so would
> leave stale passthrough bits behind if the guest LBR event is no longer
> active.
>
> vmx_recalc_msr_intercepts() is invoked in response to
> KVM_REQ_RECALC_INTERCEPTS, which is raised on MSR filter updates, but it
> skips the LBR MSRs, and vmx_enable_lbr_msrs_passthrough() does nothing
> if lbr_desc->msr_passthrough is already set. If the LBR MSRs are passed
> through when userspace installs a filter that denies them, they remain
> passed through, and the guest can access them without exiting to
> userspace. Conversely, if a filter forced interception when the guest
> LBR event became active, relaxing the filter leaves the MSRs needlessly
> intercepted. Either way, the bitmap remains stale until the guest LBR
> event is torn down and recreated.
>
> Only x2APIC MSRs are exempt from userspace filtering (see
> kvm_msr_allowed() and the KVM_X86_SET_MSR_FILTER documentation), and the
> filter is honored when LBR passthrough is first enabled, so KVM's
> behavior shouldn't depend on whether the filter is set before or after
> the guest enables LBRs. Drop the LBR MSRs from the comment claiming
> that they can't be filtered by userspace, and clarify that
> lbr_desc.msr_passthrough tracks KVM's desired interception, which may
> not match the MSR bitmap when userspace filters are in play.
>
> Fixes: 9254beaafd12 ("KVM: vmx/pmu: Reduce the overhead of LBR pass-through or cancellation")
> Cc: stable@vger.kernel.org
Meh, this isn't stable material. Unlike SVM, where LBR virtualization is tied
to a pile of other crud, if userspace wants to filter LBRs on Intel it should
just not expose LBRs in the first place.
If it weren't for SVM, and the fact that avoiding the filters is actually more
work, I probably would vote to fix the docs.
> Signed-off-by: Jim Mattson <jmattson@google.com>
> ---
> arch/x86/kvm/vmx/pmu_intel.c | 20 +++++++++++++++++++-
> arch/x86/kvm/vmx/pmu_intel.h | 7 ++++++-
> arch/x86/kvm/vmx/vmx.c | 6 ++++--
> arch/x86/kvm/vmx/vmx.h | 1 +
> 4 files changed, 30 insertions(+), 4 deletions(-)
>
> diff --git a/arch/x86/kvm/vmx/pmu_intel.c b/arch/x86/kvm/vmx/pmu_intel.c
> index 70a8c4816135..b945213f0b68 100644
> --- a/arch/x86/kvm/vmx/pmu_intel.c
> +++ b/arch/x86/kvm/vmx/pmu_intel.c
> @@ -517,7 +517,8 @@ static void intel_pmu_refresh(struct kvm_vcpu *vcpu)
> memset(&lbr_desc->records, 0, sizeof(lbr_desc->records));
>
> /*
> - * Setting passthrough of LBR MSRs is done only in the VM-Entry loop,
> + * LBR MSRs are initially passed through only in the VM-Entry loop (a
> + * full MSR intercept recalc merely refreshes an existing passthrough),
> * and PMU refresh is disallowed after the vCPU has run, i.e. this code
> * should never be reached while KVM is passing through MSRs.
> */
> @@ -704,6 +705,23 @@ static inline void vmx_enable_lbr_msrs_passthrough(struct kvm_vcpu *vcpu)
> lbr_desc->msr_passthrough = true;
> }
>
> +/*
> + * Refresh the LBR MSR intercepts if the LBRs are passed through, so that
> + * changes to userspace MSR filters are reflected in the MSR bitmap. There's
> + * nothing to do if the LBRs are intercepted, as a filter can only force
> + * interception, never prevent it.
Hmm, I don't love assuming that recalcs are only done for filter updates. On the
other hand, taking action if lbr_desc->msr_passthrough=false is nonsensical.
Rather than immediately refresh the updates, what if we just disable passthrough
and let vmx_passthrough_lbr_msrs() do the actual update?
void vmx_recalc_lbr_msr_intercepts(struct kvm_vcpu *vcpu)
{
if (WARN_ON_ONCE(!vcpu_to_lbr_desc(vcpu)))
return;
/* Disable passthrough to force a recalc on the next VM-Entry. */
vmx_disable_lbr_msrs_passthrough(vcpu);
}
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH 1/4] KVM: SVM: Always update LBR MSR intercepts on full MSR intercept recalc
2026-10-21 0:09 ` Yosry Ahmed
@ 2026-11-04 20:55 ` Sean Christopherson
0 siblings, 0 replies; 8+ messages in thread
From: Sean Christopherson @ 2026-11-04 20:55 UTC (permalink / raw)
To: Yosry Ahmed
Cc: Jim Mattson, Paolo Bonzini, kvm, linux-kernel, Like Xu, stable
On Tue, Oct 20, 2026, Yosry Ahmed wrote:
> On Tue, Oct 20, 2026 at 4:45 PM Jim Mattson <jmattson@google.com> wrote:
> > diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c
> > index fe0cba4731b2..55b3ee840365 100644
> > --- a/arch/x86/kvm/svm/svm.c
> > +++ b/arch/x86/kvm/svm/svm.c
> > @@ -721,14 +721,11 @@ void *svm_alloc_permissions_map(unsigned long size, gfp_t gfp_mask)
> > return pm;
> > }
> >
> > -static void svm_recalc_lbr_msr_intercepts(struct kvm_vcpu *vcpu)
> > +static void svm_set_lbr_msr_intercepts(struct kvm_vcpu *vcpu)
> > {
> > struct vcpu_svm *svm = to_svm(vcpu);
> > bool intercept = !(svm->vmcb->control.misc_ctl2 & SVM_MISC2_ENABLE_V_LBR);
> >
> > - if (intercept == svm->lbr_msrs_intercepted)
> > - return;
> > -
> > svm_set_intercept_for_msr(vcpu, MSR_IA32_LASTBRANCHFROMIP, MSR_TYPE_RW, intercept);
> > svm_set_intercept_for_msr(vcpu, MSR_IA32_LASTBRANCHTOIP, MSR_TYPE_RW, intercept);
> > svm_set_intercept_for_msr(vcpu, MSR_IA32_LASTINTFROMIP, MSR_TYPE_RW, intercept);
> > @@ -740,6 +737,22 @@ static void svm_recalc_lbr_msr_intercepts(struct kvm_vcpu *vcpu)
> > svm->lbr_msrs_intercepted = intercept;
>
> Hmm I was going to ask if we can set svm->lbr_msrs_intercepted based
> on whether or not svm_set_intercept_for_msr() actually set the
> intercept, so that it also captures intercepts due to MSR filtering. I
> assume that we didn't do this because MSR filters can result in
> different interception status for different LBR MSRs, and we don't
> want to track them individually?
NAK. In the past, KVM had a bitmap to do exactly that, and it was a trainwreck.
> Hmm even if we do track them individually (e.g. as a bitmap), it would
> add a bit of complexity here because we'll need to plumb that into
> svm_set_intercept_for_msr(), right?
>
> I suppose if we go with "lbr_msrs_intercepted just means KVM wants to
> intercept", then we should probably rename it accordingly?
Probably, but that can be done on top. And I'd like to change all of these flags
(all two of them?) to be consistent.
> > }
> >
> > +static void svm_recalc_lbr_msr_intercepts(struct kvm_vcpu *vcpu)
> > +{
> > + struct vcpu_svm *svm = to_svm(vcpu);
> > + bool intercept = !(svm->vmcb->control.misc_ctl2 & SVM_MISC2_ENABLE_V_LBR);
Eww. The naming is all kinda of funky, and I strongly dislike the duplicate code.
E.g. svm_set_lbr_msr_intercepts() recalcs, it's not a pure "set". I'd much rather
pass a @force param, e.g.
diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c
index e6b8c0423813..2d70fb37103e 100644
--- a/arch/x86/kvm/svm/svm.c
+++ b/arch/x86/kvm/svm/svm.c
@@ -728,12 +728,12 @@ void *svm_alloc_permissions_map(unsigned long size, gfp_t gfp_mask)
return pm;
}
-static void svm_recalc_lbr_msr_intercepts(struct kvm_vcpu *vcpu)
+static void __svm_recalc_lbr_msr_intercepts(struct kvm_vcpu *vcpu, bool force)
{
struct vcpu_svm *svm = to_svm(vcpu);
bool intercept = !(svm->vmcb->control.misc_ctl2 & SVM_MISC2_ENABLE_V_LBR);
- if (intercept == svm->lbr_msrs_intercepted)
+ if (intercept == svm->lbr_msrs_intercepted && !force)
return;
svm_set_intercept_for_msr(vcpu, MSR_IA32_LASTBRANCHFROMIP, MSR_TYPE_RW, intercept);
@@ -747,6 +747,11 @@ static void svm_recalc_lbr_msr_intercepts(struct kvm_vcpu *vcpu)
svm->lbr_msrs_intercepted = intercept;
}
+static void svm_recalc_lbr_msr_intercepts(struct kvm_vcpu *vcpu)
+{
+ __svm_recalc_lbr_msr_intercepts(vcpu, false);
+}
+
void svm_vcpu_free_msrpm(void *msrpm)
{
__free_pages(virt_to_page(msrpm), get_order(MSRPM_SIZE));
@@ -803,7 +808,7 @@ static void svm_recalc_msr_intercepts(struct kvm_vcpu *vcpu)
#endif
if (lbrv)
- svm_recalc_lbr_msr_intercepts(vcpu);
+ __svm_recalc_lbr_msr_intercepts(vcpu, true);
if (cpu_feature_enabled(X86_FEATURE_IBPB))
svm_set_intercept_for_msr(vcpu, MSR_IA32_PRED_CMD, MSR_TYPE_W,
^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [PATCH 2/4] KVM: VMX: Refresh LBR MSR intercepts on full MSR intercept recalc
2026-11-04 20:45 ` Sean Christopherson
@ 2026-11-04 23:49 ` Jim Mattson
2026-11-04 23:59 ` Jim Mattson
0 siblings, 1 reply; 8+ messages in thread
From: Jim Mattson @ 2026-11-04 23:49 UTC (permalink / raw)
To: Sean Christopherson
Cc: Paolo Bonzini, kvm, linux-kernel, Yosry Ahmed, Like Xu, stable
On Wed, Nov 4, 2026 at 12:45 PM Sean Christopherson <seanjc@google.com> wrote:
>
> On Tue, Oct 20, 2026, Jim Mattson wrote:
> > Re-apply the LBR MSR intercepts in vmx_recalc_msr_intercepts() if the
> > LBRs are currently passed through, so that changes to userspace MSR
> > filters are reflected in the MSR bitmap. Unlike SVM, which can simply
> > rewrite the intercepts in either direction, leave the bitmap alone if
> > the LBRs aren't passed through, as a filter can only force interception,
> > never prevent it, i.e. the bitmap is already correct. Note, clearing
> > msr_passthrough to force vmx_passthrough_lbr_msrs() to re-apply the
> > intercepts on the next VM-Enter isn't an option, as doing so would
> > leave stale passthrough bits behind if the guest LBR event is no longer
> > active.
> >
> > vmx_recalc_msr_intercepts() is invoked in response to
> > KVM_REQ_RECALC_INTERCEPTS, which is raised on MSR filter updates, but it
> > skips the LBR MSRs, and vmx_enable_lbr_msrs_passthrough() does nothing
> > if lbr_desc->msr_passthrough is already set. If the LBR MSRs are passed
> > through when userspace installs a filter that denies them, they remain
> > passed through, and the guest can access them without exiting to
> > userspace. Conversely, if a filter forced interception when the guest
> > LBR event became active, relaxing the filter leaves the MSRs needlessly
> > intercepted. Either way, the bitmap remains stale until the guest LBR
> > event is torn down and recreated.
> >
> > Only x2APIC MSRs are exempt from userspace filtering (see
> > kvm_msr_allowed() and the KVM_X86_SET_MSR_FILTER documentation), and the
> > filter is honored when LBR passthrough is first enabled, so KVM's
> > behavior shouldn't depend on whether the filter is set before or after
> > the guest enables LBRs. Drop the LBR MSRs from the comment claiming
> > that they can't be filtered by userspace, and clarify that
> > lbr_desc.msr_passthrough tracks KVM's desired interception, which may
> > not match the MSR bitmap when userspace filters are in play.
> >
> > Fixes: 9254beaafd12 ("KVM: vmx/pmu: Reduce the overhead of LBR pass-through or cancellation")
> > Cc: stable@vger.kernel.org
>
> Meh, this isn't stable material. Unlike SVM, where LBR virtualization is tied
> to a pile of other crud, if userspace wants to filter LBRs on Intel it should
> just not expose LBRs in the first place.
The functionality is not equivalent. For whatever reason, MSR
filtering can be modified dynamically.
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH 2/4] KVM: VMX: Refresh LBR MSR intercepts on full MSR intercept recalc
2026-11-04 23:49 ` Jim Mattson
@ 2026-11-04 23:59 ` Jim Mattson
2026-11-05 0:25 ` Sean Christopherson
0 siblings, 1 reply; 8+ messages in thread
From: Jim Mattson @ 2026-11-04 23:59 UTC (permalink / raw)
To: Sean Christopherson
Cc: Paolo Bonzini, kvm, linux-kernel, Yosry Ahmed, Like Xu, stable
On Wed, Nov 4, 2026 at 3:49 PM Jim Mattson <jmattson@google.com> wrote:
>
> On Wed, Nov 4, 2026 at 12:45 PM Sean Christopherson <seanjc@google.com> wrote:
> >
> > On Tue, Oct 20, 2026, Jim Mattson wrote:
> > > Re-apply the LBR MSR intercepts in vmx_recalc_msr_intercepts() if the
> > > LBRs are currently passed through, so that changes to userspace MSR
> > > filters are reflected in the MSR bitmap. Unlike SVM, which can simply
> > > rewrite the intercepts in either direction, leave the bitmap alone if
> > > the LBRs aren't passed through, as a filter can only force interception,
> > > never prevent it, i.e. the bitmap is already correct. Note, clearing
> > > msr_passthrough to force vmx_passthrough_lbr_msrs() to re-apply the
> > > intercepts on the next VM-Enter isn't an option, as doing so would
> > > leave stale passthrough bits behind if the guest LBR event is no longer
> > > active.
> > >
> > > vmx_recalc_msr_intercepts() is invoked in response to
> > > KVM_REQ_RECALC_INTERCEPTS, which is raised on MSR filter updates, but it
> > > skips the LBR MSRs, and vmx_enable_lbr_msrs_passthrough() does nothing
> > > if lbr_desc->msr_passthrough is already set. If the LBR MSRs are passed
> > > through when userspace installs a filter that denies them, they remain
> > > passed through, and the guest can access them without exiting to
> > > userspace. Conversely, if a filter forced interception when the guest
> > > LBR event became active, relaxing the filter leaves the MSRs needlessly
> > > intercepted. Either way, the bitmap remains stale until the guest LBR
> > > event is torn down and recreated.
> > >
> > > Only x2APIC MSRs are exempt from userspace filtering (see
> > > kvm_msr_allowed() and the KVM_X86_SET_MSR_FILTER documentation), and the
> > > filter is honored when LBR passthrough is first enabled, so KVM's
> > > behavior shouldn't depend on whether the filter is set before or after
> > > the guest enables LBRs. Drop the LBR MSRs from the comment claiming
> > > that they can't be filtered by userspace, and clarify that
> > > lbr_desc.msr_passthrough tracks KVM's desired interception, which may
> > > not match the MSR bitmap when userspace filters are in play.
> > >
> > > Fixes: 9254beaafd12 ("KVM: vmx/pmu: Reduce the overhead of LBR pass-through or cancellation")
> > > Cc: stable@vger.kernel.org
> >
> > Meh, this isn't stable material. Unlike SVM, where LBR virtualization is tied
> > to a pile of other crud, if userspace wants to filter LBRs on Intel it should
> > just not expose LBRs in the first place.
>
> The functionality is not equivalent. For whatever reason, MSR
> filtering can be modified dynamically.
Oh, and, duh, MSR filtering doesn't disallow the LBRs; it just
reflects them to userspace.
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH 2/4] KVM: VMX: Refresh LBR MSR intercepts on full MSR intercept recalc
2026-11-04 23:59 ` Jim Mattson
@ 2026-11-05 0:25 ` Sean Christopherson
0 siblings, 0 replies; 8+ messages in thread
From: Sean Christopherson @ 2026-11-05 0:25 UTC (permalink / raw)
To: Jim Mattson
Cc: Paolo Bonzini, kvm, linux-kernel, Yosry Ahmed, Like Xu, stable
On Wed, Nov 04, 2026, Jim Mattson wrote:
> On Wed, Nov 4, 2026 at 3:49 PM Jim Mattson <jmattson@google.com> wrote:
> >
> > On Wed, Nov 4, 2026 at 12:45 PM Sean Christopherson <seanjc@google.com> wrote:
> > >
> > > On Tue, Oct 20, 2026, Jim Mattson wrote:
> > > > Re-apply the LBR MSR intercepts in vmx_recalc_msr_intercepts() if the
> > > > LBRs are currently passed through, so that changes to userspace MSR
> > > > filters are reflected in the MSR bitmap. Unlike SVM, which can simply
> > > > rewrite the intercepts in either direction, leave the bitmap alone if
> > > > the LBRs aren't passed through, as a filter can only force interception,
> > > > never prevent it, i.e. the bitmap is already correct. Note, clearing
> > > > msr_passthrough to force vmx_passthrough_lbr_msrs() to re-apply the
> > > > intercepts on the next VM-Enter isn't an option, as doing so would
> > > > leave stale passthrough bits behind if the guest LBR event is no longer
> > > > active.
> > > >
> > > > vmx_recalc_msr_intercepts() is invoked in response to
> > > > KVM_REQ_RECALC_INTERCEPTS, which is raised on MSR filter updates, but it
> > > > skips the LBR MSRs, and vmx_enable_lbr_msrs_passthrough() does nothing
> > > > if lbr_desc->msr_passthrough is already set. If the LBR MSRs are passed
> > > > through when userspace installs a filter that denies them, they remain
> > > > passed through, and the guest can access them without exiting to
> > > > userspace. Conversely, if a filter forced interception when the guest
> > > > LBR event became active, relaxing the filter leaves the MSRs needlessly
> > > > intercepted. Either way, the bitmap remains stale until the guest LBR
> > > > event is torn down and recreated.
> > > >
> > > > Only x2APIC MSRs are exempt from userspace filtering (see
> > > > kvm_msr_allowed() and the KVM_X86_SET_MSR_FILTER documentation), and the
> > > > filter is honored when LBR passthrough is first enabled, so KVM's
> > > > behavior shouldn't depend on whether the filter is set before or after
> > > > the guest enables LBRs. Drop the LBR MSRs from the comment claiming
> > > > that they can't be filtered by userspace, and clarify that
> > > > lbr_desc.msr_passthrough tracks KVM's desired interception, which may
> > > > not match the MSR bitmap when userspace filters are in play.
> > > >
> > > > Fixes: 9254beaafd12 ("KVM: vmx/pmu: Reduce the overhead of LBR pass-through or cancellation")
> > > > Cc: stable@vger.kernel.org
> > >
> > > Meh, this isn't stable material. Unlike SVM, where LBR virtualization is tied
> > > to a pile of other crud, if userspace wants to filter LBRs on Intel it should
> > > just not expose LBRs in the first place.
> >
> > The functionality is not equivalent. For whatever reason, MSR
> > filtering can be modified dynamically.
>
> Oh, and, duh, MSR filtering doesn't disallow the LBRs; it just
> reflects them to userspace.
Right, but how many real world deployments actually enable vLBR *and* want to
intercept accesses *and* want to do so dynamically? This isn't a particularly
dangerous change by any means, but sending things to stable@ does incur some
amount of downstream work. Unless there's an actual end user that's affected by
this flaw, I'd much prefer not to create more work.
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2026-11-05 0:25 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
[not found] <20261020234535.3182385-1-jmattson@google.com>
2026-10-20 23:45 ` [PATCH 1/4] KVM: SVM: Always update LBR MSR intercepts on full MSR intercept recalc Jim Mattson
2026-10-21 0:09 ` Yosry Ahmed
2026-11-04 20:55 ` Sean Christopherson
2026-10-20 23:45 ` [PATCH 2/4] KVM: VMX: Refresh " Jim Mattson
2026-11-04 20:45 ` Sean Christopherson
2026-11-04 23:49 ` Jim Mattson
2026-11-04 23:59 ` Jim Mattson
2026-11-05 0:25 ` Sean Christopherson
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox