[PATCH] KVM: VMX: Use _safe MSR accessors in LBR handler

From: xuanqingshi

Date: Tue May 26 2026 - 13:46:51 EST


From: Xuanqing Shi <1356292400@xxxxxx>

intel_pmu_handle_lbr_msrs_access() uses rdmsrq()/wrmsrq() to directly
access LBR-related MSRs on the physical CPU. If the guest provides an
out-of-range or otherwise invalid MSR index, the unchecked access
triggers a #GP fault, resulting in an "unchecked MSR access error"
warning and a host crash when panic_on_warn is enabled.

The crash was observed in a nested virtualization setup where a
VMCS-targeted fuzzer triggered a WRMSR to MSR 0x1c8 (LBR_SELECT)
that propagated through the PMU emulation path to the physical host:

unchecked MSR access error: WRMSR to 0x1c8
(tried to write 0x0000000000004000)
Call Trace:
? native_write_msr+0x4/0x30
? intel_pmu_handle_lbr_msrs_access+0xff/0x120 [kvm_intel]
intel_pmu_set_msr+0x4e0/0x7f0 [kvm_intel]
kvm_pmu_set_msr+0x17e/0x1c0 [kvm]
kvm_set_msr_common+0xc76/0x1440 [kvm]
vmx_set_msr+0x5e6/0x1570 [kvm_intel]
kvm_emulate_wrmsr+0x54/0x1d0 [kvm]
vmx_handle_exit+0x7fc/0x970 [kvm_intel]

Replace rdmsrq()/wrmsrq() with their _safe variants so that invalid
MSR accesses are caught gracefully and reported back to the guest as
errors instead of crashing the host.

Found by a VMCS-targeted fuzzer based on syzkaller.

Fixes: 1b5ac3226a1a ("KVM: vmx/pmu: Pass-through LBR msrs when the guest LBR event is ACTIVE")
Signed-off-by: Xuanqing Shi <1356292400@xxxxxx>
---
arch/x86/kvm/vmx/pmu_intel.c | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/arch/x86/kvm/vmx/pmu_intel.c b/arch/x86/kvm/vmx/pmu_intel.c
index 27eb76e6b6a0..94d2cbffcff4 100644
--- a/arch/x86/kvm/vmx/pmu_intel.c
+++ b/arch/x86/kvm/vmx/pmu_intel.c
@@ -293,6 +293,7 @@ static bool intel_pmu_handle_lbr_msrs_access(struct kvm_vcpu *vcpu,
{
struct lbr_desc *lbr_desc = vcpu_to_lbr_desc(vcpu);
u32 index = msr_info->index;
+ int err;

if (!intel_pmu_is_valid_lbr_msr(vcpu, index))
return false;
@@ -309,12 +310,12 @@ static bool intel_pmu_handle_lbr_msrs_access(struct kvm_vcpu *vcpu,
local_irq_disable();
if (lbr_desc->event->state == PERF_EVENT_STATE_ACTIVE) {
if (read)
- rdmsrq(index, msr_info->data);
+ err = rdmsrq_safe(index, &msr_info->data);
else
- wrmsrq(index, msr_info->data);
+ err = wrmsrq_safe(index, msr_info->data);
__set_bit(INTEL_PMC_IDX_FIXED_VLBR, vcpu_to_pmu(vcpu)->pmc_in_use);
local_irq_enable();
- return true;
+ return !err;
}
clear_bit(INTEL_PMC_IDX_FIXED_VLBR, vcpu_to_pmu(vcpu)->pmc_in_use);
local_irq_enable();
--
2.25.1