[PATCH 0/4] KVM: x86: Honor userspace MSR filter changes for passed-through LBR MSRs
From: Jim Mattson
Date: Tue Oct 20 2026 - 19:46:13 EST
When userspace installs a new MSR filter, KVM raises
KVM_REQ_RECALC_INTERCEPTS to rebuild the MSR intercept bitmaps. However,
both SVM and VMX cache the desired interception state for the LBR MSRs,
and skip updating the bitmap when the cached state hasn't changed. The
cached state doesn't account for the filter, so a filter that denies
access to LBR MSRs that are already passed through never takes effect,
i.e. the guest can continue to read and write the MSRs without exiting
to userspace. Conversely, if a filter forced interception when the
LBRs were passed through, relaxing the filter leaves the MSRs needlessly
intercepted.
On SVM, the bug was introduced by commit 3fa05f96fc08 ("KVM: SVM: Fix
redundant updates of LBR MSR intercepts"). On VMX, it goes all the way
back to commit 9254beaafd12 ("KVM: vmx/pmu: Reduce the overhead of LBR
pass-through or cancellation"). The comment in
vmx_recalc_msr_intercepts() claiming that LBR MSRs "cannot be filtered
by userspace" is at odds with both kvm_msr_allowed() and the
KVM_X86_SET_MSR_FILTER documentation, which exempt only the x2APIC MSRs.
It's also at odds with the filter actually being applied when the LBRs
are first passed through.
Patches 1 and 2 fix SVM and VMX, respectively. Patch 3 adds a selftests
helper to request permission for a dynamic XSAVE feature without
skipping the test if the feature is unavailable. Patch 4 adds a test
that primes as many of KVM's passthrough paths as is practical (LBRs,
SPEC_CTRL, XFD, APERF/MPERF, etc.), and then cycles through every
possible transition between "allow all," "deny reads," "deny writes,"
and "deny both," verifying that every denied access (and only denied
accesses) exits to userspace.
Without patch 1, the new test fails on an AMD Genoa host with lbrv=1:
both RDMSR and WRMSR of all four LBR MSRs (0x1db-0x1de) are still passed
through after the first deny-all filter is installed. Similarly,
without patch 2, the test fails on an Intel Ice Lake host: both RDMSR
and WRMSR of MSR_LBR_SELECT, MSR_LBR_TOS, MSR_LBR_NHM_FROM,
MSR_LBR_NHM_TO, and MSR_LBR_INFO_0 are still passed through after the
first deny-all filter is installed. With the full series, the test
passes on both hosts.
The selftest is intentionally broader than the LBR MSRs, in the hope of
catching future "skip the update if nothing changed" optimizations that
forget about userspace MSR filters. Intel PT MSRs aren't covered, as
priming them requires the guest to be actively tracing.
Jim Mattson (4):
KVM: SVM: Always update LBR MSR intercepts on full MSR intercept
recalc
KVM: VMX: Refresh LBR MSR intercepts on full MSR intercept recalc
KVM: selftests: Add a helper to request XSAVE permission without
skipping
KVM: selftests: Verify MSR filter changes apply to passed-through MSRs
arch/x86/kvm/svm/svm.c | 28 +-
arch/x86/kvm/svm/svm.h | 6 +
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 +
tools/testing/selftests/kvm/Makefile.kvm | 1 +
.../selftests/kvm/include/x86/processor.h | 4 +
.../testing/selftests/kvm/lib/x86/processor.c | 33 +-
.../kvm/x86/msr_filter_update_test.c | 392 ++++++++++++++++++
10 files changed, 478 insertions(+), 20 deletions(-)
create mode 100644 tools/testing/selftests/kvm/x86/msr_filter_update_test.c
base-commit: 24a19b953e2a3d0ea5a8c4951a0ab8f32720c907
--
2.56.0.212.g129ede20d9-goog