[PATCH 2/6] KVM: x86: Fix CPUID range check for Centaur and Hypervisor ranges

From: Sean Christopherson
Date: Mon Mar 02 2020 - 14:58:07 EST


Extend the mask in cpuid_function_in_range() for finding the "class" of
the function to 0xfffffff00. While there is no official definition of
what constitutes a class, e.g. arguably bits 31:16 should be the class
and bits 15:0 the functions within that class, the Hypervisor logic
effectively uses bits 31:8 as the class by virtue of checking for
different bases in increments of 0x100, e.g. KVM advertises its CPUID
functions starting at 0x40000100 when HyperV features are advertised at
the default base of 0x40000000.

Masking against 0x80000000 only handles basic and extended leafs, which
results in Centaur and Hypervisor range checks being performed against
the basic CPUID range, e.g. if CPUID.0x40000000.EAX=0x4000000A and there
is no entry for CPUID.0x40000006, then function 0x40000006 would be
incorrectly reported as out of bounds.

The bad range check doesn't cause function problems for any known VMM
because out-of-range semantics only come into play if the exact entry
isn't found, and VMMs either support a very limited Hypervisor range,
e.g. the official KVM range is 0x40000000-0x40000001 (effectively no
room for undefined leafs) or explicitly defines gaps to be zero, e.g.
Qemu explicitly creates zeroed entries up to the Cenatur and Hypervisor
limits (the latter comes into play when providing HyperV features).

The bad behavior can be visually confirmed by dumping CPUID output in
the guest when running Qemu with a stable TSC, as Qemu extends the limit
of range 0x40000000 to 0x40000010 to advertise VMware's cpuid_freq,
without defining zeroed entries for 0x40000002 - 0x4000000f.

Fixes: 43561123ab37 ("kvm: x86: Improve emulation of CPUID leaves 0BH and 1FH")
Cc: Jim Mattson <jmattson@xxxxxxxxxx>
Signed-off-by: Sean Christopherson <sean.j.christopherson@xxxxxxxxx>
---
arch/x86/kvm/cpuid.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c
index 6be012937eba..c320126e0118 100644
--- a/arch/x86/kvm/cpuid.c
+++ b/arch/x86/kvm/cpuid.c
@@ -993,7 +993,7 @@ static bool cpuid_function_in_range(struct kvm_vcpu *vcpu, u32 function)
{
struct kvm_cpuid_entry2 *max;

- max = kvm_find_cpuid_entry(vcpu, function & 0x80000000, 0);
+ max = kvm_find_cpuid_entry(vcpu, function & 0xffffff00u, 0);
return max && function <= max->eax;
}

--
2.24.1