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:18:05 +0000 (19:18 +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 fcfa3fedf84f11efa98e661adf24fab16df27571..45a3d11bb70d98c0c366b9e7b9699a6939c271e4 100644 (file)
@@ -184,6 +184,10 @@ module_param(force_emulation_prefix, bool, S_IRUGO);
 int __read_mostly pi_inject_timer = -1;
 module_param(pi_inject_timer, bint, S_IRUGO | S_IWUSR);
 
+/* 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
@@ -4164,10 +4168,15 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
                r = KVM_CLOCK_TSC_STABLE;
                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,
@@ -5746,15 +5755,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:
@@ -12796,6 +12816,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);