• Roman Kagan's avatar
    KVM: x86/pmu: Truncate counter value to allowed width on write · b29a2acd
    Roman Kagan authored
    Performance counters are defined to have width less than 64 bits.  The
    vPMU code maintains the counters in u64 variables but assumes the value
    to fit within the defined width.  However, for Intel non-full-width
    counters (MSR_IA32_PERFCTRx) the value receieved from the guest is
    truncated to 32 bits and then sign-extended to full 64 bits.  If a
    negative value is set, it's sign-extended to 64 bits, but then in
    kvm_pmu_incr_counter() it's incremented, truncated, and compared to the
    previous value for overflow detection.
    
    That previous value is not truncated, so it always evaluates bigger than
    the truncated new one, and a PMI is injected.  If the PMI handler writes
    a negative counter value itself, the vCPU never quits the PMI loop.
    
    Turns out that Linux PMI handler actually does write the counter with
    the value just read with RDPMC, so when no full-width support is exposed
    via MSR_IA32_PERF_CAPABILITIES, and the guest initializes the counter to
    a negative value, it locks up.
    
    This has been observed in the field, for example, when the guest configures
    atop to use perfevents and runs two instances of it simultaneously.
    
    To address the problem, maintain the invariant that the counter value
    always fits in the defined bit width, by truncating the received value
    in the respective set_msr methods.  For better readability, factor the
    out into a helper function, pmc_write_counter(), shared by vmx and svm
    parts.
    
    Fixes: 9cd803d4 ("KVM: x86: Update vPMCs when retiring instructions")
    Cc: stable@vger.kernel.org
    Signed-off-by: default avatarRoman Kagan <rkagan@amazon.de>
    Link: https://lore.kernel.org/all/20230504120042.785651-1-rkagan@amazon.deTested-by: default avatarLike Xu <likexu@tencent.com>
    [sean: tweak changelog, s/set/write in the helper]
    Signed-off-by: default avatarSean Christopherson <seanjc@google.com>
    b29a2acd
pmu.h 8.04 KB