From 3164f3976a6d26f671e4165ed097b5ce7ac0d1c9 Mon Sep 17 00:00:00 2001 From: Yonghua Huang Date: Tue, 2 Jul 2019 14:06:09 +0800 Subject: [PATCH] hv: Mitigation for CPU MDS vulnerabilities. Microarchitectural Data Sampling (MDS) is a hardware vulnerability which allows unprivileged speculative access to data which is available in various CPU internal buffers. 1. Mitigation on ACRN: 1) Microcode update is required. 2) Clear CPU internal buffers (store buffer, load buffer and load port) if current CPU is affected by MDS, when VM entry to avoid any information leakage to guest thru above buffers. 3) Mitigation is not needed if ARCH_CAP_MDS_NO bit (bit5) is set in IA32_ARCH_CAPABILITIES MSR (10AH), in this case, current processor is no affected by MDS vulnerability, in other cases mitigation for MDS is required. 2. Methods to clear CPU buffers (microcode update is required): 1) L1D cache flush 2) VERW instruction Either of above operations will trigger clearing all CPU internal buffers if this CPU is affected by MDS. Above mechnism is enumerated by: CPUID.(EAX=7H, ECX=0):EDX[MD_CLEAR=10]. 3. Mitigation details on ACRN: if (processor is affected by MDS) if (processor is not affected by L1TF OR L1D flush is not launched on VM Entry) execute VERW instruction when VM entry. endif endif 4. Referrence: Deep Dive: Intel Analysis of Microarchitectural Data Sampling https://software.intel.com/security-software-guidance/insights/ deep-dive-intel-analysis-microarchitectural-data-sampling Deep Dive: CPUID Enumeration and Architectural MSRs https://software.intel.com/security-software-guidance/insights/ deep-dive-cpuid-enumeration-and-architectural-msrs Tracked-On: #3317 Signed-off-by: Yonghua Huang Reviewed-by: Anthony Xu Reviewed-by: Jason CJ Chen --- hypervisor/arch/x86/guest/vcpu.c | 6 +++ hypervisor/arch/x86/security.c | 61 +++++++++++++++++++++++ hypervisor/include/arch/x86/cpufeatures.h | 1 + hypervisor/include/arch/x86/msr.h | 1 + hypervisor/include/arch/x86/security.h | 1 + 5 files changed, 70 insertions(+) diff --git a/hypervisor/arch/x86/guest/vcpu.c b/hypervisor/arch/x86/guest/vcpu.c index 5fdb960b7..68e1b8798 100644 --- a/hypervisor/arch/x86/guest/vcpu.c +++ b/hypervisor/arch/x86/guest/vcpu.c @@ -485,6 +485,9 @@ int32_t run_vcpu(struct acrn_vcpu *vcpu) cpu_l1d_flush(); #endif + /*Mitigation for MDS vulnerability, overwrite CPU internal buffers */ + cpu_internal_buffers_clear(); + /* Launch the VM */ status = vmx_vmrun(ctx, VM_LAUNCH, ibrs_type); @@ -507,6 +510,9 @@ int32_t run_vcpu(struct acrn_vcpu *vcpu) cpu_l1d_flush(); #endif + /* Mitigation for MDS vulnerability, overwrite CPU internal buffers */ + cpu_internal_buffers_clear(); + /* Resume the VM */ status = vmx_vmrun(ctx, VM_RESUME, ibrs_type); } diff --git a/hypervisor/arch/x86/security.c b/hypervisor/arch/x86/security.c index 50215b57a..d16f2a773 100644 --- a/hypervisor/arch/x86/security.c +++ b/hypervisor/arch/x86/security.c @@ -14,6 +14,7 @@ #include static bool skip_l1dfl_vmentry; +static bool cpu_md_clear; static int32_t ibrs_type; static void detect_ibrs(void) @@ -51,6 +52,7 @@ int32_t get_ibrs_type(void) bool check_cpu_security_cap(void) { bool ret = true; + bool mds_no = false; uint64_t x86_arch_capabilities; detect_ibrs(); @@ -59,6 +61,8 @@ bool check_cpu_security_cap(void) x86_arch_capabilities = msr_read(MSR_IA32_ARCH_CAPABILITIES); skip_l1dfl_vmentry = ((x86_arch_capabilities & IA32_ARCH_CAP_SKIP_L1DFL_VMENTRY) != 0UL); + + mds_no = ((x86_arch_capabilities & IA32_ARCH_CAP_MDS_NO) != 0UL); } if ((!pcpu_has_cap(X86_FEATURE_L1D_FLUSH)) && (!skip_l1dfl_vmentry)) { @@ -72,6 +76,25 @@ bool check_cpu_security_cap(void) ret = false; } + if (!mds_no) { /* Processor is affected by MDS vulnerability.*/ + if (pcpu_has_cap(X86_FEATURE_MDS_CLEAR)) { + cpu_md_clear = true; +#ifdef CONFIG_L1D_FLUSH_VMENTRY_ENABLED + if (!skip_l1dfl_vmentry) { + /* L1D cache flush will also overwrite CPU internal buffers, + * additional MDS buffers clear operation is not required. + */ + cpu_md_clear = false; + } +#endif + } else { + /* Processor is affected by MDS but no mitigation software + * interface is enumerated, CPU microcode need to be udpated. + */ + ret = false; + } + } + return ret; } @@ -90,6 +113,44 @@ void cpu_l1d_flush(void) } +/* + * VERW instruction (with microcode update) will overwrite + * CPU internal buffers. + */ +static inline void verw_buffer_overwriting(void) +{ + uint16_t ds = HOST_GDT_RING0_DATA_SEL; + + asm volatile ("verw %[ds]" : : [ds] "m" (ds) : "cc"); +} + +/* + * On processors that enumerate MD_CLEAR:CPUID.(EAX=7H,ECX=0):EDX[MD_CLEAR=10], + * the VERW instruction or L1D_FLUSH command should be used to cause the + * processor to overwrite buffer values that are affected by MDS + * (Microarchitectural Data Sampling) vulnerabilities. + * + * The VERW instruction and L1D_FLUSH command will overwrite below buffer values: + * - Store buffer value for the current logical processor on processors affected + * by MSBDS (Microarchitectural Store Buffer Data Sampling). + * - Fill buffer for all logical processors on the physical core for processors + * affected by MFBDS (Microarchitectural Fill Buffer Data Sampling). + * - Load port for all logical processors on the physical core for processors + * affected by MLPDS(Microarchitectural Load Port Data Sampling). + * + * If processor is affected by L1TF vulnerability and the mitigation is enabled, + * L1D_FLUSH will overwrite internal buffers on processors affected by MDS, no + * additional buffer overwriting is required before VM entry. For other cases, + * VERW instruction is used to overwrite buffer values for processors affected + * by MDS. + */ +void cpu_internal_buffers_clear(void) +{ + if (cpu_md_clear) { + verw_buffer_overwriting(); + } +} + #ifdef STACK_PROTECTOR static uint64_t get_random_value(void) { diff --git a/hypervisor/include/arch/x86/cpufeatures.h b/hypervisor/include/arch/x86/cpufeatures.h index bbf83a596..aeeae03de 100644 --- a/hypervisor/include/arch/x86/cpufeatures.h +++ b/hypervisor/include/arch/x86/cpufeatures.h @@ -79,6 +79,7 @@ #define X86_FEATURE_CLFLUSHOPT ((FEAT_7_0_EBX << 5U) + 23U) /* Intel-defined CPU features, CPUID level 0x00000007 (EDX)*/ +#define X86_FEATURE_MDS_CLEAR ((FEAT_7_0_EDX << 5U) + 10U) #define X86_FEATURE_IBRS_IBPB ((FEAT_7_0_EDX << 5U) + 26U) #define X86_FEATURE_STIBP ((FEAT_7_0_EDX << 5U) + 27U) #define X86_FEATURE_L1D_FLUSH ((FEAT_7_0_EDX << 5U) + 28U) diff --git a/hypervisor/include/arch/x86/msr.h b/hypervisor/include/arch/x86/msr.h index 195c97d68..1eea6a1a3 100644 --- a/hypervisor/include/arch/x86/msr.h +++ b/hypervisor/include/arch/x86/msr.h @@ -630,6 +630,7 @@ void update_msr_bitmap_x2apic_passthru(struct acrn_vcpu *vcpu); #define IA32_ARCH_CAP_RSBA (1U << 2U) #define IA32_ARCH_CAP_SKIP_L1DFL_VMENTRY (1U << 3U) #define IA32_ARCH_CAP_SSB_NO (1U << 4U) +#define IA32_ARCH_CAP_MDS_NO (1U << 5U) /* Flush L1 D-cache */ #define IA32_L1D_FLUSH (1UL << 0U) diff --git a/hypervisor/include/arch/x86/security.h b/hypervisor/include/arch/x86/security.h index 38f0e0b40..5180b8eb0 100644 --- a/hypervisor/include/arch/x86/security.h +++ b/hypervisor/include/arch/x86/security.h @@ -20,6 +20,7 @@ int32_t get_ibrs_type(void); void cpu_l1d_flush(void); bool check_cpu_security_cap(void); +void cpu_internal_buffers_clear(void); #ifdef STACK_PROTECTOR struct stack_canary {