KVM: x86: Reject disabling of MWAIT/HLT interception when not allowed
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 <kechenl@nvidia.com> Fixes:4d5422cea3("KVM: X86: Provide a capability to disable MWAIT intercepts") Fixes:6f0f2d5ef8("KVM: x86: Mitigate the cross-thread return address predictions bug") Reviewed-by: Maxim Levitsky <mlevitsk@redhat.com> Reviewed-by: Xiaoyao Li <xiaoyao.li@intel.com> Link: https://lore.kernel.org/r/20241128013424.4096668-15-seanjc@google.com Signed-off-by: Sean Christopherson <seanjc@google.com>
This commit is contained in:
+28
-26
@@ -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 @@ split_irqchip_unlock:
|
||||
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);
|
||||
|
||||
Reference in New Issue
Block a user