[PATCH 3/4] KVM: x86: Recompute EFER.LMA instead of inheriting the current value on EFER writes
From: Sean Christopherson
Date: Thu Oct 22 2026 - 18:31:39 EST
Recompute EFER.LMA on bare writes to EFER (via WRMSR or KVM_SET_MSRS)
instead of carrying forward the current EFER.LMA. While it _should_ be
impossible for EFER.LMA to end up in an inconsistent state on such a write,
KVM has had a rash of exactly those bugs, mostly because SVM is quite lax
when it comes to consistenty checks, which in turn bleeds into KVM's nested
SVM implementation. Retaining the existing EFER is also rather confusing,
as understanding why keeping EFER.LMA is correct requires a lot of a priori
knowledge of both x86-64 and KVM.
Keep the core concept of the existing logic as a sanity check: WARN and
reject the write if the computed EFER.LMA would be toggled, because as
described above, that _should_ be impossible.
Signed-off-by: Sean Christopherson <seanjc@xxxxxxxxxx>
---
arch/x86/kvm/msrs.c | 14 ++++++++++++--
1 file changed, 12 insertions(+), 2 deletions(-)
diff --git a/arch/x86/kvm/msrs.c b/arch/x86/kvm/msrs.c
index c3cb1575fe66..41f3ec6eb286 100644
--- a/arch/x86/kvm/msrs.c
+++ b/arch/x86/kvm/msrs.c
@@ -638,8 +638,18 @@ static int set_efer(struct kvm_vcpu *vcpu, u64 efer)
(vcpu->arch.efer & EFER_SVME) && !(efer & EFER_SVME))
return 1;
- efer &= ~EFER_LMA;
- efer |= vcpu->arch.efer & EFER_LMA;
+ if ((efer & EFER_LME) && is_paging(vcpu) && is_pae(vcpu))
+ efer |= EFER_LMA;
+ else
+ efer &= ~EFER_LMA;
+
+ /*
+ * Toggling EFER.LMA on a bare write to EFER should be impossible, as
+ * it means KVM allowed architecturally invalid state at some point in
+ * the past, i.e. allowed EFER.LMA=1 && (!CR0.PG || !CR4.PAE).
+ */
+ if (WARN_ON_ONCE((efer & EFER_LMA) != (vcpu->arch.efer & EFER_LMA)))
+ return 1;
r = kvm_x86_call(set_efer)(vcpu, efer);
if (r) {
--
2.56.0.257.gf7497c7d27-goog