KVM: x86: Mitigate the cross-thread return address predictions bug
authorTom Lendacky <thomas.lendacky@amd.com>
Thu, 9 Feb 2023 15:22:25 +0000 (09:22 -0600)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 14 Feb 2023 18:11:56 +0000 (19:11 +0100)
commit 6f0f2d5ef895d66a3f2b32dd05189ec34afa5a55 upstream.

By default, KVM/SVM will intercept attempts by the guest to transition
out of C0. However, the KVM_CAP_X86_DISABLE_EXITS capability can be used
by a VMM to change this behavior. To mitigate the cross-thread return
address predictions bug (X86_BUG_SMT_RSB), a VMM must not be allowed to
override the default behavior to intercept C0 transitions.

Use a module parameter to control the mitigation on processors that are
vulnerable to X86_BUG_SMT_RSB. If the processor is vulnerable to the
X86_BUG_SMT_RSB bug and the module parameter is set to mitigate the bug,
KVM will not allow the disabling of the HLT, MWAIT and CSTATE exits.

Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
Message-Id: <4019348b5e07148eb4d593380a5f6713b93c9a16.1675956146.git.thomas.lendacky@amd.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
arch/x86/kvm/x86.c

index 69227f7..a0c35b9 100644 (file)
@@ -192,6 +192,10 @@ module_param(enable_pmu, bool, 0444);
 bool __read_mostly eager_page_split = true;
 module_param(eager_page_split, bool, 0644);
 
+/* Enable/disable SMT_RSB bug mitigation */
+bool __read_mostly mitigate_smt_rsb;
+module_param(mitigate_smt_rsb, bool, 0444);
+
 /*
  * Restoring the host value for MSRs that are only consumed when running in
  * usermode, e.g. SYSCALL MSRs and TSC_AUX, can be deferred until the CPU
@@ -4435,10 +4439,15 @@ 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_HLT | KVM_X86_DISABLE_EXITS_PAUSE |
-                     KVM_X86_DISABLE_EXITS_CSTATE;
-               if(kvm_can_mwait_in_guest())
-                       r |= KVM_X86_DISABLE_EXITS_MWAIT;
+               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;
+               }
                break;
        case KVM_CAP_X86_SMM:
                /* SMBASE is usually relocated above 1M on modern chipsets,
@@ -6214,15 +6223,26 @@ split_irqchip_unlock:
                if (cap->args[0] & ~KVM_X86_DISABLE_VALID_EXITS)
                        break;
 
-               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_PAUSE)
                        kvm->arch.pause_in_guest = true;
-               if (cap->args[0] & KVM_X86_DISABLE_EXITS_CSTATE)
-                       kvm->arch.cstate_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;
+               }
+
                r = 0;
                break;
        case KVM_CAP_MSR_PLATFORM_INFO:
@@ -13730,6 +13750,7 @@ EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_vmgexit_msr_protocol_exit);
 static int __init kvm_x86_init(void)
 {
        kvm_mmu_x86_module_init();
+       mitigate_smt_rsb &= boot_cpu_has_bug(X86_BUG_SMT_RSB) && cpu_smt_possible();
        return 0;
 }
 module_init(kvm_x86_init);