From f91c5ea970675637721bb7f18adaa189837eb783 Mon Sep 17 00:00:00 2001 From: Andrew Cooper Date: Mon, 22 May 2023 23:03:00 +0100 Subject: [PATCH] x86/amd: Mitigations for Zenbleed MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Zenbleed is a malfunction on AMD Zen2 uarch parts which results in corruption of the vector registers. An attacker can trigger this bug deliberately in order to access stale data in the physical vector register file. This can include data from sibling threads, or a higher-privilege context. Microcode is the preferred mitigation but in the case that's not available use the chickenbit as instructed by AMD. Re-evaluate the mitigation on late microcode load too. This is XSA-433 / CVE-2023-20593. Signed-off-by: Andrew Cooper Acked-by: Roger Pau Monné --- xen/arch/x86/cpu/amd.c | 69 ++++++++++++++++++++++++++++ xen/arch/x86/cpu/microcode/amd.c | 2 + xen/arch/x86/include/asm/processor.h | 2 + 3 files changed, 73 insertions(+) diff --git a/xen/arch/x86/cpu/amd.c b/xen/arch/x86/cpu/amd.c index 0eaef82e51..3ed06f6704 100644 --- a/xen/arch/x86/cpu/amd.c +++ b/xen/arch/x86/cpu/amd.c @@ -13,6 +13,7 @@ #include #include #include +#include #include "cpu.h" @@ -905,6 +906,72 @@ void __init detect_zen2_null_seg_behaviour(void) } +void amd_check_zenbleed(void) +{ + const struct cpu_signature *sig = &this_cpu(cpu_sig); + unsigned int good_rev, chickenbit = (1 << 9); + uint64_t val, old_val; + + /* + * If we're virtualised, we can't do family/model checks safely, and + * we likely wouldn't have access to DE_CFG even if we could see a + * microcode revision. + * + * A hypervisor may hide AVX as a stopgap mitigation. We're not in a + * position to care either way. An admin doesn't want to be disabling + * AVX as a mitigation on any build of Xen with this logic present. + */ + if (cpu_has_hypervisor || boot_cpu_data.x86 != 0x17) + return; + + switch (boot_cpu_data.x86_model) { + case 0x30 ... 0x3f: good_rev = 0x0830107a; break; + case 0x60 ... 0x67: good_rev = 0x0860010b; break; + case 0x68 ... 0x6f: good_rev = 0x08608105; break; + case 0x70 ... 0x7f: good_rev = 0x08701032; break; + case 0xa0 ... 0xaf: good_rev = 0x08a00008; break; + default: + /* + * With the Fam17h check above, parts getting here are Zen1. + * They're not affected. + */ + return; + } + + rdmsrl(MSR_AMD64_DE_CFG, val); + old_val = val; + + /* + * Microcode is the preferred mitigation, in terms of performance. + * However, without microcode, this chickenbit (specific to the Zen2 + * uarch) disables Floating Point Mov-Elimination to mitigate the + * issue. + */ + val &= ~chickenbit; + if (sig->rev < good_rev) + val |= chickenbit; + + if (val == old_val) + /* Nothing to change. */ + return; + + /* + * DE_CFG is a Core-scoped MSR, and this write is racy during late + * microcode load. However, both threads calculate the new value from + * state which is shared, and unrelated to the old value, so the + * result should be consistent. + */ + wrmsrl(MSR_AMD64_DE_CFG, val); + + /* + * Inform the admin that we changed something, but don't spam, + * especially during a late microcode load. + */ + if (smp_processor_id() == 0) + printk(XENLOG_INFO "Zenbleed mitigation - using %s\n", + val & chickenbit ? "chickenbit" : "microcode"); +} + static void cf_check init_amd(struct cpuinfo_x86 *c) { u32 l, h; @@ -1171,6 +1238,8 @@ static void cf_check init_amd(struct cpuinfo_x86 *c) if ((smp_processor_id() == 1) && !cpu_has(c, X86_FEATURE_ITSC)) disable_c1_ramping(); + amd_check_zenbleed(); + check_syscfg_dram_mod_en(); amd_log_freq(c); diff --git a/xen/arch/x86/cpu/microcode/amd.c b/xen/arch/x86/cpu/microcode/amd.c index a9a5557835..75fc84e445 100644 --- a/xen/arch/x86/cpu/microcode/amd.c +++ b/xen/arch/x86/cpu/microcode/amd.c @@ -262,6 +262,8 @@ static int cf_check apply_microcode(const struct microcode_patch *patch) "microcode: CPU%u updated from revision %#x to %#x, date = %04x-%02x-%02x\n", cpu, old_rev, rev, patch->year, patch->month, patch->day); + amd_check_zenbleed(); + return 0; } diff --git a/xen/arch/x86/include/asm/processor.h b/xen/arch/x86/include/asm/processor.h index 3b3cf51814..c0529cc3d9 100644 --- a/xen/arch/x86/include/asm/processor.h +++ b/xen/arch/x86/include/asm/processor.h @@ -547,6 +547,8 @@ enum ap_boot_method { }; extern enum ap_boot_method ap_boot_method; +void amd_check_zenbleed(void); + #endif /* !__ASSEMBLY__ */ #endif /* __ASM_X86_PROCESSOR_H */