KVM: VMX: Allow userspace to set all supported FEATURE_CONTROL bits
authorSean Christopherson <seanjc@google.com>
Tue, 7 Jun 2022 23:23:51 +0000 (23:23 +0000)
committerSean Christopherson <seanjc@google.com>
Thu, 1 Dec 2022 00:29:53 +0000 (16:29 -0800)
Allow userspace to set all supported bits in MSR IA32_FEATURE_CONTROL
irrespective of the guest CPUID model, e.g. via KVM_SET_MSRS.  KVM's ABI
is that userspace is allowed to set MSRs before CPUID, i.e. can set MSRs
to values that would fault according to the guest CPUID model.

Signed-off-by: Sean Christopherson <seanjc@google.com>
Link: https://lore.kernel.org/r/20220607232353.3375324-2-seanjc@google.com
arch/x86/kvm/vmx/vmx.c

index 3f31c46..7be1fb5 100644 (file)
@@ -1836,12 +1836,38 @@ bool nested_vmx_allowed(struct kvm_vcpu *vcpu)
        return nested && guest_cpuid_has(vcpu, X86_FEATURE_VMX);
 }
 
-static inline bool vmx_feature_control_msr_valid(struct kvm_vcpu *vcpu,
-                                                uint64_t val)
+/*
+ * Userspace is allowed to set any supported IA32_FEATURE_CONTROL regardless of
+ * guest CPUID.  Note, KVM allows userspace to set "VMX in SMX" to maintain
+ * backwards compatibility even though KVM doesn't support emulating SMX.  And
+ * because userspace set "VMX in SMX", the guest must also be allowed to set it,
+ * e.g. if the MSR is left unlocked and the guest does a RMW operation.
+ */
+#define KVM_SUPPORTED_FEATURE_CONTROL  (FEAT_CTL_LOCKED                         | \
+                                       FEAT_CTL_VMX_ENABLED_INSIDE_SMX  | \
+                                       FEAT_CTL_VMX_ENABLED_OUTSIDE_SMX | \
+                                       FEAT_CTL_SGX_LC_ENABLED          | \
+                                       FEAT_CTL_SGX_ENABLED             | \
+                                       FEAT_CTL_LMCE_ENABLED)
+
+static inline bool vmx_feature_control_msr_valid(struct vcpu_vmx *vmx,
+                                                struct msr_data *msr)
 {
-       uint64_t valid_bits = to_vmx(vcpu)->msr_ia32_feature_control_valid_bits;
+       uint64_t valid_bits;
+
+       /*
+        * Ensure KVM_SUPPORTED_FEATURE_CONTROL is updated when new bits are
+        * exposed to the guest.
+        */
+       WARN_ON_ONCE(vmx->msr_ia32_feature_control_valid_bits &
+                    ~KVM_SUPPORTED_FEATURE_CONTROL);
+
+       if (msr->host_initiated)
+               valid_bits = KVM_SUPPORTED_FEATURE_CONTROL;
+       else
+               valid_bits = vmx->msr_ia32_feature_control_valid_bits;
 
-       return !(val & ~valid_bits);
+       return !(msr->data & ~valid_bits);
 }
 
 static int vmx_get_msr_feature(struct kvm_msr_entry *msr)
@@ -2240,7 +2266,7 @@ static int vmx_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
                vcpu->arch.mcg_ext_ctl = data;
                break;
        case MSR_IA32_FEAT_CTL:
-               if (!vmx_feature_control_msr_valid(vcpu, data) ||
+               if (!vmx_feature_control_msr_valid(vmx, msr_info) ||
                    (to_vmx(vcpu)->msr_ia32_feature_control &
                     FEAT_CTL_LOCKED && !msr_info->host_initiated))
                        return 1;