cpuid_query_maxphyaddr() returns CPUID.0x80000008.EAX[7:0] as the guest's physical-address width without any sanity check. KVM computes the reserved GPA bits from that value, e.g. kvm_vcpu_reserved_gpa_bits_raw() is rsvd_bits(maxphyaddr, 63), and rsvd_bits() returns 0 when the bit range is empty. A VMM that populates CPUID.0x80000008.EAX above 52 therefore makes KVM stop treating the upper bits of guest PTEs as reserved: reserved-bit fault checking on guest page table walks silently degenerates, and garbage nCR3s/PDPTRs are accepted instead of faulting. A MAXPHYADDR above 52 is architecturally impossible on x86-64; clamp the queried value to 52 so that a buggy VMM configuration degrades to a (very wide) but still meaningful physical-address width instead of disabling KVM's reserved-bit accounting. This is hardening rather than a security fix: the actor is the VMM, which already owns the guest, so an over-wide MAXPHYADDR is not a privilege boundary crossing. The motivation is correctness, not containment: a configuration value outside architectural limits should not silently change how KVM validates guest page tables, and clamping keeps the degenerate case well-defined instead of subtly disabling a whole class of fault checks. The unclamped read predates the introduction of the cached value; no Fixes: tag is attached for that reason. Signed-off-by: Pablo Azuaje --- arch/x86/kvm/cpuid.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c index 851f151efb35..f0166072968f 100644 --- a/arch/x86/kvm/cpuid.c +++ b/arch/x86/kvm/cpuid.c @@ -477,8 +477,18 @@ int cpuid_query_maxphyaddr(struct kvm_vcpu *vcpu) if (!best || best->eax < 0x80000008) goto not_found; best = kvm_find_cpuid_entry(vcpu, 0x80000008); - if (best) - return best->eax & 0xff; + if (best) { + /* + * Clamp MAXPHYADDR to the architectural maximum of 52 bits. + * A larger value is a VMM bug: KVM derives the reserved GPA + * bits from MAXPHYADDR, e.g. kvm_vcpu_reserved_gpa_bits_raw() + * is rsvd_bits(maxphyaddr, 63), and rsvd_bits() returns 0 + * when the range is empty, i.e. an over-wide MAXPHYADDR + * silently disables reserved-bit checks on guest page table + * walks. + */ + return min_t(u32, best->eax & 0xff, 52); + } not_found: return 36; } -- 2.53.0