]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/commitdiff
KVM: x86/speculation: Disable Fill buffer clear within guests
authorPawan Gupta <pawan.kumar.gupta@linux.intel.com>
Fri, 20 May 2022 03:35:15 +0000 (20:35 -0700)
committerThadeu Lima de Souza Cascardo <cascardo@canonical.com>
Thu, 9 Jun 2022 14:21:14 +0000 (11:21 -0300)
commit 027bbb884be006b05d9c577d6401686053aa789e upstream

The enumeration of MD_CLEAR in CPUID(EAX=7,ECX=0).EDX{bit 10} is not an
accurate indicator on all CPUs of whether the VERW instruction will
overwrite fill buffers. FB_CLEAR enumeration in
IA32_ARCH_CAPABILITIES{bit 17} covers the case of CPUs that are not
vulnerable to MDS/TAA, indicating that microcode does overwrite fill
buffers.

Guests running in VMM environments may not be aware of all the
capabilities/vulnerabilities of the host CPU. Specifically, a guest may
apply MDS/TAA mitigations when a virtual CPU is enumerated as vulnerable
to MDS/TAA even when the physical CPU is not. On CPUs that enumerate
FB_CLEAR_CTRL the VMM may set FB_CLEAR_DIS to skip overwriting of fill
buffers by the VERW instruction. This is done by setting FB_CLEAR_DIS
during VMENTER and resetting on VMEXIT. For guests that enumerate
FB_CLEAR (explicitly asking for fill buffer clear capability) the VMM
will not use FB_CLEAR_DIS.

Irrespective of guest state, host overwrites CPU buffers before VMENTER
to protect itself from an MMIO capable guest, as part of mitigation for
MMIO Stale Data vulnerabilities.

Signed-off-by: Pawan Gupta <pawan.kumar.gupta@linux.intel.com>
Signed-off-by: Borislav Petkov <bp@suse.de>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
CVE-2022-21166
CVE-2022-21123
CVE-2022-21125
Signed-off-by: Thadeu Lima de Souza Cascardo <cascardo@canonical.com>
arch/x86/include/asm/msr-index.h
arch/x86/kvm/vmx/vmx.c
arch/x86/kvm/vmx/vmx.h
arch/x86/kvm/x86.c
tools/arch/x86/include/asm/msr-index.h

index 2c83d062b14943777802d2e377d919a57695733e..4aa9701e0018f1ce73413175c14ba2f81b74a0b6 100644 (file)
                                                 * VERW clears CPU fill buffer
                                                 * even on MDS_NO CPUs.
                                                 */
+#define ARCH_CAP_FB_CLEAR_CTRL         BIT(18) /*
+                                                * MSR_IA32_MCU_OPT_CTRL[FB_CLEAR_DIS]
+                                                * bit available to control VERW
+                                                * behavior.
+                                                */
 
 #define MSR_IA32_FLUSH_CMD             0x0000010b
 #define L1D_FLUSH                      BIT(0)  /*
 #define MSR_IA32_MCU_OPT_CTRL          0x00000123
 #define RNGDS_MITG_DIS                 BIT(0)  /* SRBDS support */
 #define RTM_ALLOW                      BIT(1)  /* TSX development mode */
+#define FB_CLEAR_DIS                   BIT(3)  /* CPU Fill buffer clear disable */
 
 #define MSR_IA32_SYSENTER_CS           0x00000174
 #define MSR_IA32_SYSENTER_ESP          0x00000175
index f80921f28509faa08db38a8e81da8a6a278f0928..9c9792f5a1f4d9d08f5b54e01fe7e2c1e09d0f9c 100644 (file)
@@ -226,6 +226,9 @@ static const struct {
 #define L1D_CACHE_ORDER 4
 static void *vmx_l1d_flush_pages;
 
+/* Control for disabling CPU Fill buffer clear */
+static bool __read_mostly vmx_fb_clear_ctrl_available;
+
 static int vmx_setup_l1d_flush(enum vmx_l1d_flush_state l1tf)
 {
        struct page *page;
@@ -357,6 +360,60 @@ static int vmentry_l1d_flush_get(char *s, const struct kernel_param *kp)
        return sprintf(s, "%s\n", vmentry_l1d_param[l1tf_vmx_mitigation].option);
 }
 
+static void vmx_setup_fb_clear_ctrl(void)
+{
+       u64 msr;
+
+       if (boot_cpu_has(X86_FEATURE_ARCH_CAPABILITIES) &&
+           !boot_cpu_has_bug(X86_BUG_MDS) &&
+           !boot_cpu_has_bug(X86_BUG_TAA)) {
+               rdmsrl(MSR_IA32_ARCH_CAPABILITIES, msr);
+               if (msr & ARCH_CAP_FB_CLEAR_CTRL)
+                       vmx_fb_clear_ctrl_available = true;
+       }
+}
+
+static __always_inline void vmx_disable_fb_clear(struct vcpu_vmx *vmx)
+{
+       u64 msr;
+
+       if (!vmx->disable_fb_clear)
+               return;
+
+       rdmsrl(MSR_IA32_MCU_OPT_CTRL, msr);
+       msr |= FB_CLEAR_DIS;
+       wrmsrl(MSR_IA32_MCU_OPT_CTRL, msr);
+       /* Cache the MSR value to avoid reading it later */
+       vmx->msr_ia32_mcu_opt_ctrl = msr;
+}
+
+static __always_inline void vmx_enable_fb_clear(struct vcpu_vmx *vmx)
+{
+       if (!vmx->disable_fb_clear)
+               return;
+
+       vmx->msr_ia32_mcu_opt_ctrl &= ~FB_CLEAR_DIS;
+       wrmsrl(MSR_IA32_MCU_OPT_CTRL, vmx->msr_ia32_mcu_opt_ctrl);
+}
+
+static void vmx_update_fb_clear_dis(struct kvm_vcpu *vcpu, struct vcpu_vmx *vmx)
+{
+       vmx->disable_fb_clear = vmx_fb_clear_ctrl_available;
+
+       /*
+        * If guest will not execute VERW, there is no need to set FB_CLEAR_DIS
+        * at VMEntry. Skip the MSR read/write when a guest has no use case to
+        * execute VERW.
+        */
+       if ((vcpu->arch.arch_capabilities & ARCH_CAP_FB_CLEAR) ||
+          ((vcpu->arch.arch_capabilities & ARCH_CAP_MDS_NO) &&
+           (vcpu->arch.arch_capabilities & ARCH_CAP_TAA_NO) &&
+           (vcpu->arch.arch_capabilities & ARCH_CAP_PSDP_NO) &&
+           (vcpu->arch.arch_capabilities & ARCH_CAP_FBSDP_NO) &&
+           (vcpu->arch.arch_capabilities & ARCH_CAP_SBDR_SSDP_NO)))
+               vmx->disable_fb_clear = false;
+}
+
 static const struct kernel_param_ops vmentry_l1d_flush_ops = {
        .set = vmentry_l1d_flush_set,
        .get = vmentry_l1d_flush_get,
@@ -2228,6 +2285,10 @@ static int vmx_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
                        ret = kvm_set_msr_common(vcpu, msr_info);
        }
 
+       /* FB_CLEAR may have changed, also update the FB_CLEAR_DIS behavior */
+       if (msr_index == MSR_IA32_ARCH_CAPABILITIES)
+               vmx_update_fb_clear_dis(vcpu, vmx);
+
        return ret;
 }
 
@@ -4445,6 +4506,8 @@ static void vmx_vcpu_reset(struct kvm_vcpu *vcpu, bool init_event)
        kvm_make_request(KVM_REQ_APIC_PAGE_RELOAD, vcpu);
 
        vpid_sync_context(vmx->vpid);
+
+       vmx_update_fb_clear_dis(vcpu, vmx);
 }
 
 static void vmx_enable_irq_window(struct kvm_vcpu *vcpu)
@@ -6612,6 +6675,8 @@ static noinstr void vmx_vcpu_enter_exit(struct kvm_vcpu *vcpu,
                 kvm_arch_has_assigned_device(vcpu->kvm))
                mds_clear_cpu_buffers();
 
+       vmx_disable_fb_clear(vmx);
+
        if (vcpu->arch.cr2 != native_read_cr2())
                native_write_cr2(vcpu->arch.cr2);
 
@@ -6620,6 +6685,8 @@ static noinstr void vmx_vcpu_enter_exit(struct kvm_vcpu *vcpu,
 
        vcpu->arch.cr2 = native_read_cr2();
 
+       vmx_enable_fb_clear(vmx);
+
        kvm_guest_exit_irqoff();
 }
 
@@ -8037,6 +8104,8 @@ static int __init vmx_init(void)
                return r;
        }
 
+       vmx_setup_fb_clear_ctrl();
+
        for_each_possible_cpu(cpu) {
                INIT_LIST_HEAD(&per_cpu(loaded_vmcss_on_cpu, cpu));
 
index 3f9c8548625d66797b6a586f518dd2fb2f7326ec..ee057cf6ce999969c636ff0df25a3c3366cd7445 100644 (file)
@@ -325,6 +325,8 @@ struct vcpu_vmx {
        u64 msr_ia32_feature_control_valid_bits;
        /* SGX Launch Control public key hash */
        u64 msr_ia32_sgxlepubkeyhash[4];
+       u64 msr_ia32_mcu_opt_ctrl;
+       bool disable_fb_clear;
 
        struct pt_desc pt_desc;
        struct lbr_desc lbr_desc;
index 39e641b87eed19c20f3e5a490aeafe7b4b141718..62298046ea34ad5ddd263d2ec88c47c2b7ea0a60 100644 (file)
@@ -1510,6 +1510,9 @@ static u64 kvm_get_arch_capabilities(void)
                 */
        }
 
+       /* Guests don't need to know "Fill buffer clear control" exists */
+       data &= ~ARCH_CAP_FB_CLEAR_CTRL;
+
        return data;
 }
 
index 0e64872fd070db28958a5dd34746af469a46348c..7dc5a3306f37a7d8c1d6686007b340b7f106ee9a 100644 (file)
                                                 * VERW clears CPU fill buffer
                                                 * even on MDS_NO CPUs.
                                                 */
+#define ARCH_CAP_FB_CLEAR_CTRL         BIT(18) /*
+                                                * MSR_IA32_MCU_OPT_CTRL[FB_CLEAR_DIS]
+                                                * bit available to control VERW
+                                                * behavior.
+                                                */
 
 #define MSR_IA32_FLUSH_CMD             0x0000010b
 #define L1D_FLUSH                      BIT(0)  /*
 #define MSR_IA32_MCU_OPT_CTRL          0x00000123
 #define RNGDS_MITG_DIS                 BIT(0)  /* SRBDS support */
 #define RTM_ALLOW                      BIT(1)  /* TSX development mode */
+#define FB_CLEAR_DIS                   BIT(3)  /* CPU Fill buffer clear disable */
 
 #define MSR_IA32_SYSENTER_CS           0x00000174
 #define MSR_IA32_SYSENTER_ESP          0x00000175