Commit c829ccd4 authored by Sean Christopherson's avatar Sean Christopherson
Browse files

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: 4d5422ce ("KVM: X86: Provide a capability to disable MWAIT intercepts")
Fixes: 6f0f2d5e ("KVM: x86: Mitigate the cross-thread return address predictions bug")
Reviewed-by: default avatarMaxim Levitsky <mlevitsk@redhat.com>
Reviewed-by: default avatarXiaoyao Li <xiaoyao.li@intel.com>
Link: https://lore.kernel.org/r/20241128013424.4096668-15-seanjc@google.com


Signed-off-by: default avatarSean Christopherson <seanjc@google.com>
parent 04cd8f86
Loading
Loading
Loading
Loading
+28 −26
Original line number Diff line number Diff line
@@ -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() &&
		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_MWAIT) &&
			    kvm_can_mwait_in_guest())
		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);