Kernel KVM virtualization development
 help / color / mirror / Atom feed
* [PATCH] KVM: x86: Clamp guest MAXPHYADDR to the architectural maximum
@ 2026-10-18 11:52 Pablo Azuaje
  2026-10-20 13:39 ` Sean Christopherson
  0 siblings, 1 reply; 2+ messages in thread
From: Pablo Azuaje @ 2026-10-18 11:52 UTC (permalink / raw)
  To: Paolo Bonzini, Sean Christopherson; +Cc: kvm, linux-kernel, Eugene Korenevsky

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 <pablo45154@gmail.com>
---
 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


^ permalink raw reply related	[flat|nested] 2+ messages in thread

* Re: [PATCH] KVM: x86: Clamp guest MAXPHYADDR to the architectural maximum
  2026-10-18 11:52 [PATCH] KVM: x86: Clamp guest MAXPHYADDR to the architectural maximum Pablo Azuaje
@ 2026-10-20 13:39 ` Sean Christopherson
  0 siblings, 0 replies; 2+ messages in thread
From: Sean Christopherson @ 2026-10-20 13:39 UTC (permalink / raw)
  To: Pablo Azuaje; +Cc: Paolo Bonzini, kvm, linux-kernel, Eugene Korenevsky

On Sun, Oct 18, 2026, Pablo Azuaje wrote:
> 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.

Unless there is a danger to the host, this isn't something I care to fix.  As I
said here[*] and in many other threads:

 : In other words, userspace owns the vCPU model, and for good reasons.  KVM needs
 : to allow userspace to define a sane model, but with *very* few exceptions, KVM
 : should not try to "help" userspace by stuffing bits.
 : 
 : Pretty much everytime KVM tries to help, it causes problems.  E.g. initializing
 : perf_capabilities to kvm_caps.supported_perf_cap seems like a good thing, except
 : it presents a bogus model if userspace decides to not enumerate a vPMU to the
 : guest (Aaron was allegedly going to send a patch for this...).

There are myriad ways for the VMM to misconfigure the guest, and there are also
legitimate reasons why userspace may want to do something that KVM thinks is odd.

If for some reason we do need to "fix" this, I would want to reject KVM_SET_CPUID{,2},
not silently clobber the vCPU model.  But that's a big "if", because AFAICT there
is no danger to the host.

[*] https://lore.kernel.org/all/ZQ3Z25cu5gnsedqr@google.com

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2026-10-20 13:39 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-18 11:52 [PATCH] KVM: x86: Clamp guest MAXPHYADDR to the architectural maximum Pablo Azuaje
2026-10-20 13:39 ` Sean Christopherson

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox