mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Sean Christopherson <seanjc@google.com>
To: Paolo Bonzini <pbonzini@redhat.com>,
	Sean Christopherson <seanjc@google.com>
Cc: kvm@vger.kernel.org, linux-kernel@vger.kernel.org,
	 Mahmoud Abumandour <ma.mandourr@gmail.com>
Subject: [PATCH v3 4/5] KVM: nVMX: Take full ownership of the post-VMXON CR{0,4} must-be-1 bits
Date: Fri, 30 Oct 2026 14:37:46 -0700	[thread overview]
Message-ID: <20261030213747.2611815-5-seanjc@google.com> (raw)
In-Reply-To: <20261030213747.2611815-1-seanjc@google.com>

Effectively drop support for restoring/stuffing fixed-0 CR{0,4} MSRs, as
restoring to anything other than KVM's hardcoded value is broken, and is
absolutely not worth fixing.  KVM doesn't adjust the "guest owned" masks
based on the MSR values, and so if userspace were to require any of the
passed-through bits to be '1', KVM would fail to prevent the guest from
clearing a must-be-1 bit.

Even worse, if userspace disables KVM_X86_QUIRK_STUFF_FEATURE_MSRS without
ever setting the CR{0,4} FIXED0 MSRs, then KVM would allow running with an
impossible configuration, as KVM would advertise to L1 that there are *no*
must-be-1 bits, but couldn't honor that because VM-Entry would fail due to
the bits still being must-be-1 in real hardware.  E.g. KVM would tell the
guest that CR4.VMXE can be toggled at will, in complete violation of VMXON.

Don't try to fix KVM, as no known VMM sets values other than KVM's own
hardcoded value.  KVM already requires the incoming value be a superset of
KVM's value, i.e. KVM doesn't allowed reducing the set of must-be-1 bits,
and so it's only possible for userspace to require *extra* bits to always
be 1.  Drop KVM's "support" before anyone tries to utilize it, e.g. to
harden a guest or something, as honoring things like CR0.TS in particular
would be painful, e.g. KVM would need to handle CLTS interception.

Signed-off-by: Sean Christopherson <seanjc@google.com>
---
 Documentation/virt/kvm/api.rst                |  9 +++---
 arch/x86/kvm/vmx/nested.c                     | 30 ++-----------------
 arch/x86/kvm/vmx/vmx.c                        |  3 ++
 .../selftests/kvm/x86/feature_msrs_test.c     |  2 +-
 4 files changed, 11 insertions(+), 33 deletions(-)

diff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst
index e95c9cda085d..c9f7284f76b4 100644
--- a/Documentation/virt/kvm/api.rst
+++ b/Documentation/virt/kvm/api.rst
@@ -8764,10 +8764,11 @@ KVM_X86_QUIRK_STUFF_FEATURE_MSRS           By default, at vCPU creation, KVM set
                                            i.e. treats the feature MSRs like CPUID
                                            leaves and gives userspace full control of
                                            the vCPU model definition.  This quirk does
-                                           not affect VMX MSRs CR0/CR4_FIXED1 (0x487
-                                           and 0x489), as KVM does now allow them to
-                                           be set by userspace (KVM sets them based on
-                                           guest CPUID, for safety purposes).
+                                           not affect VMX MSRs CR0/CR4_FIXED{0,1}
+                                           (0x486 - 0x489), as KVM does now allow them
+                                           to be set by userspace (KVM sets them based
+                                           on the virtual CPU model, for simplicity and
+                                           safety purposes).
 
 KVM_X86_QUIRK_IGNORE_GUEST_PAT             By default, on Intel platforms, KVM ignores
                                            guest PAT and forces the effective memory
diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c
index 9b0bfa2f854c..a5547ec78846 100644
--- a/arch/x86/kvm/vmx/nested.c
+++ b/arch/x86/kvm/vmx/nested.c
@@ -1508,33 +1508,6 @@ static int vmx_restore_vmx_ept_vpid_cap(struct vcpu_vmx *vmx, u64 data)
 	return 0;
 }
 
-static u64 *vmx_get_fixed0_msr(struct nested_vmx_msrs *msrs, u32 msr_index)
-{
-	switch (msr_index) {
-	case MSR_IA32_VMX_CR0_FIXED0:
-		return &msrs->cr0_fixed0;
-	case MSR_IA32_VMX_CR4_FIXED0:
-		return &msrs->cr4_fixed0;
-	default:
-		BUG();
-	}
-}
-
-static int vmx_restore_fixed0_msr(struct vcpu_vmx *vmx, u32 msr_index, u64 data)
-{
-	const u64 *msr = vmx_get_fixed0_msr(&vmcs_config.nested, msr_index);
-
-	/*
-	 * 1 bits (which indicates bits which "must-be-1" during VMX operation)
-	 * must be 1 in the restored value.
-	 */
-	if (!is_bitwise_subset(data, *msr, -1ULL))
-		return -EINVAL;
-
-	*vmx_get_fixed0_msr(&vmx->nested.msrs, msr_index) = data;
-	return 0;
-}
-
 /*
  * Called when userspace is restoring VMX MSRs.
  *
@@ -1577,8 +1550,9 @@ int vmx_set_vmx_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 data)
 	case MSR_IA32_VMX_MISC:
 		return vmx_restore_vmx_misc(vmx, data);
 	case MSR_IA32_VMX_CR0_FIXED0:
+		return data && data != vmcs_config.nested.cr0_fixed0;
 	case MSR_IA32_VMX_CR4_FIXED0:
-		return vmx_restore_fixed0_msr(vmx, msr_index, data);
+		return data && data != vmcs_config.nested.cr4_fixed0;
 	case MSR_IA32_VMX_CR0_FIXED1:
 	case MSR_IA32_VMX_CR4_FIXED1:
 		/*
diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c
index 68c1361a92d1..4afbb3986a4c 100644
--- a/arch/x86/kvm/vmx/vmx.c
+++ b/arch/x86/kvm/vmx/vmx.c
@@ -7712,7 +7712,10 @@ static void nested_vmx_cr_fixed1_bits_update(struct kvm_vcpu *vcpu)
 	struct vcpu_vmx *vmx = to_vmx(vcpu);
 	struct kvm_cpuid_entry2 *entry;
 
+	vmx->nested.msrs.cr0_fixed0 = vmcs_config.nested.cr0_fixed0;
 	vmx->nested.msrs.cr0_fixed1 = 0xffffffff;
+
+	vmx->nested.msrs.cr4_fixed0 = vmcs_config.nested.cr4_fixed0;
 	vmx->nested.msrs.cr4_fixed1 = X86_CR4_PCE;
 
 #define cr4_fixed1_update(_cr4_mask, _reg, _cpuid_mask) do {		\
diff --git a/tools/testing/selftests/kvm/x86/feature_msrs_test.c b/tools/testing/selftests/kvm/x86/feature_msrs_test.c
index d56d0ddb3a57..837fee78835c 100644
--- a/tools/testing/selftests/kvm/x86/feature_msrs_test.c
+++ b/tools/testing/selftests/kvm/x86/feature_msrs_test.c
@@ -14,7 +14,7 @@
 
 static bool is_kvm_controlled_msr(u32 msr)
 {
-	return msr == MSR_IA32_VMX_CR0_FIXED1 || msr == MSR_IA32_VMX_CR4_FIXED1;
+	return msr >= MSR_IA32_VMX_CR0_FIXED0 && msr <= MSR_IA32_VMX_CR4_FIXED1;
 }
 
 /*
-- 
2.56.0.385.gac671c819a-goog


  parent reply	other threads:[~2026-10-30 21:37 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-30 21:37 [PATCH v3 0/5] KVM: nVMX: Honor L1-owned CR0 bits for LMSW Sean Christopherson
2026-10-30 21:37 ` [PATCH v3 1/5] KVM: nVMX: Preserve L1-owned bits in CR{0,4} read shadows Sean Christopherson
2026-10-30 21:37 ` [PATCH v3 2/5] KVM: nVMX: Honor L1-owned CR0 bits when emulating intercepted LMSW for L2 Sean Christopherson
2026-10-30 21:37 ` [PATCH v3 3/5] KVM: nVMX: Synthesize #GP if L2 writes a "bad" CR0 value via LMSW Sean Christopherson
2026-10-30 21:37 ` Sean Christopherson [this message]
2026-10-30 21:37 ` [PATCH v3 5/5] KVM: selftests: Verify KVM handling of L1-owned CR0 bits on writes from L2 Sean Christopherson

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20261030213747.2611815-5-seanjc@google.com \
    --to=seanjc@google.com \
    --cc=kvm@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=ma.mandourr@gmail.com \
    --cc=pbonzini@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®