]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
KVM: VMX: Handle bad values on proxied writes to LBR MSRs
authorXuanqing Shi <1356292400@qq.com>
Wed, 27 May 2026 02:26:17 +0000 (19:26 -0700)
committerSean Christopherson <seanjc@google.com>
Wed, 27 May 2026 23:41:51 +0000 (16:41 -0700)
Use the "safe" WRMSR API when writing LBRs on behalf of the guest (or host
userspace), and propagate any errors back to the instigator, as the value
being written is untrusted.  E.g. if the guest (or host userspace) attempts
to set reserved bits in LBR_SELECT, then KVM needs to return an error, and
not WARN on the bad value.

Continue using the "unsafe" version of RDMSR, as it should be impossible to
reach the helper with a completely bogus MSR, i.e. WARNing on RDMSR failure
is very desirable, e.g. to make KVM bugs more visible.

  unchecked MSR access error: WRMSR to 0x1c8 (tried to write 0x0000000000004000)
  Call Trace:
   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]

Fixes: 1b5ac3226a1a ("KVM: vmx/pmu: Pass-through LBR msrs when the guest LBR event is ACTIVE")
Cc: stable@vger.kernel.org
Signed-off-by: Xuanqing Shi <1356292400@qq.com>
[sean: rework changelog, only modify WRMSR path, tag for stable@]
Link: https://patch.msgid.link/20260527022617.3973884-1-seanjc@google.com
Signed-off-by: Sean Christopherson <seanjc@google.com>
arch/x86/kvm/vmx/pmu_intel.c

index 27eb76e6b6a034b8089360c76f61c8b0898671d6..22138c487216e52952143e04a904aa474834e60b 100644 (file)
@@ -308,13 +308,15 @@ static bool intel_pmu_handle_lbr_msrs_access(struct kvm_vcpu *vcpu,
         */
        local_irq_disable();
        if (lbr_desc->event->state == PERF_EVENT_STATE_ACTIVE) {
+               int err = 0;
+
                if (read)
                        rdmsrq(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();