Reject KVM_CAP_X86_DISABLE_EXITS if userspace attempts to disable MWAIT or
HLT exits and KVM previously reported (via KVM_CHECK_EXTENSION) that
disabling the exit(s) is not allowed.  E.g. because MWAIT isn't supported
or the CPU doesn't have an always-running APIC timer, or because KVM is
configured to mitigate cross-thread vulnerabilities.

Cc: Kechen Lu <kech...@nvidia.com>
Fixes: 4d5422cea3b6 ("KVM: X86: Provide a capability to disable MWAIT 
intercepts")
Fixes: 6f0f2d5ef895 ("KVM: x86: Mitigate the cross-thread return address 
predictions bug")
Reviewed-by: Maxim Levitsky <mlevi...@redhat.com>
Reviewed-by: Xiaoyao Li <xiaoyao...@intel.com>
Signed-off-by: Sean Christopherson <sea...@google.com>
---
 arch/x86/kvm/x86.c | 54 ++++++++++++++++++++++++----------------------
 1 file changed, 28 insertions(+), 26 deletions(-)

diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index c517d26f2c5b..9b7f8047f896 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -4531,6 +4531,20 @@ static inline bool kvm_can_mwait_in_guest(void)
                boot_cpu_has(X86_FEATURE_ARAT);
 }
 
+static u64 kvm_get_allowed_disable_exits(void)
+{
+       u64 r = KVM_X86_DISABLE_EXITS_PAUSE;
+
+       if (!mitigate_smt_rsb) {
+               r |= KVM_X86_DISABLE_EXITS_HLT |
+                       KVM_X86_DISABLE_EXITS_CSTATE;
+
+               if (kvm_can_mwait_in_guest())
+                       r |= KVM_X86_DISABLE_EXITS_MWAIT;
+       }
+       return r;
+}
+
 #ifdef CONFIG_KVM_HYPERV
 static int kvm_ioctl_get_supported_hv_cpuid(struct kvm_vcpu *vcpu,
                                            struct kvm_cpuid2 __user *cpuid_arg)
@@ -4673,15 +4687,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long 
ext)
                r = KVM_CLOCK_VALID_FLAGS;
                break;
        case KVM_CAP_X86_DISABLE_EXITS:
-               r = KVM_X86_DISABLE_EXITS_PAUSE;
-
-               if (!mitigate_smt_rsb) {
-                       r |= KVM_X86_DISABLE_EXITS_HLT |
-                            KVM_X86_DISABLE_EXITS_CSTATE;
-
-                       if (kvm_can_mwait_in_guest())
-                               r |= KVM_X86_DISABLE_EXITS_MWAIT;
-               }
+               r = kvm_get_allowed_disable_exits();
                break;
        case KVM_CAP_X86_SMM:
                if (!IS_ENABLED(CONFIG_KVM_SMM))
@@ -6528,33 +6534,29 @@ int kvm_vm_ioctl_enable_cap(struct kvm *kvm,
                break;
        case KVM_CAP_X86_DISABLE_EXITS:
                r = -EINVAL;
-               if (cap->args[0] & ~KVM_X86_DISABLE_VALID_EXITS)
+               if (cap->args[0] & ~kvm_get_allowed_disable_exits())
                        break;
 
                mutex_lock(&kvm->lock);
                if (kvm->created_vcpus)
                        goto disable_exits_unlock;
 
-               if (cap->args[0] & KVM_X86_DISABLE_EXITS_PAUSE)
-                       kvm->arch.pause_in_guest = true;
-
 #define SMT_RSB_MSG "This processor is affected by the Cross-Thread Return 
Predictions vulnerability. " \
                    "KVM_CAP_X86_DISABLE_EXITS should only be used with SMT 
disabled or trusted guests."
 
-               if (!mitigate_smt_rsb) {
-                       if (boot_cpu_has_bug(X86_BUG_SMT_RSB) && 
cpu_smt_possible() &&
-                           (cap->args[0] & ~KVM_X86_DISABLE_EXITS_PAUSE))
-                               pr_warn_once(SMT_RSB_MSG);
-
-                       if ((cap->args[0] & KVM_X86_DISABLE_EXITS_MWAIT) &&
-                           kvm_can_mwait_in_guest())
-                               kvm->arch.mwait_in_guest = true;
-                       if (cap->args[0] & KVM_X86_DISABLE_EXITS_HLT)
-                               kvm->arch.hlt_in_guest = true;
-                       if (cap->args[0] & KVM_X86_DISABLE_EXITS_CSTATE)
-                               kvm->arch.cstate_in_guest = true;
-               }
+               if (!mitigate_smt_rsb && boot_cpu_has_bug(X86_BUG_SMT_RSB) &&
+                   cpu_smt_possible() &&
+                   (cap->args[0] & ~KVM_X86_DISABLE_EXITS_PAUSE))
+                       pr_warn_once(SMT_RSB_MSG);
 
+               if (cap->args[0] & KVM_X86_DISABLE_EXITS_PAUSE)
+                       kvm->arch.pause_in_guest = true;
+               if (cap->args[0] & KVM_X86_DISABLE_EXITS_MWAIT)
+                       kvm->arch.mwait_in_guest = true;
+               if (cap->args[0] & KVM_X86_DISABLE_EXITS_HLT)
+                       kvm->arch.hlt_in_guest = true;
+               if (cap->args[0] & KVM_X86_DISABLE_EXITS_CSTATE)
+                       kvm->arch.cstate_in_guest = true;
                r = 0;
 disable_exits_unlock:
                mutex_unlock(&kvm->lock);
-- 
2.47.0.338.g60cca15819-goog


Reply via email to