[2/2] x86/cpu/amd: Add a Zenbleed fix
authorBorislav Petkov (AMD) <bp@alien8.de>
Sat, 15 Jul 2023 11:41:28 +0000 (13:41 +0200)
committerBen Hutchings <benh@debian.org>
Thu, 27 Jul 2023 17:28:01 +0000 (18:28 +0100)
Origin: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit?id=ed9b87010aa84c157096f98c322491e9af8e8f07
Bug-Debian-Security: https://security-tracker.debian.org/tracker/CVE-2023-20593

Upstream commit: 522b1d69219d8f083173819fde04f994aa051a98

Add a fix for the Zen2 VZEROUPPER data corruption bug where under
certain circumstances executing VZEROUPPER can cause register
corruption or leak data.

The optimal fix is through microcode but in the case the proper
microcode revision has not been applied, enable a fallback fix using
a chicken bit.

Signed-off-by: Borislav Petkov (AMD) <bp@alien8.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Gbp-Pq: Topic bugfix/x86
Gbp-Pq: Name x86-cpu-amd-Add-a-Zenbleed-fix.patch

arch/x86/include/asm/microcode.h
arch/x86/include/asm/microcode_amd.h
arch/x86/include/asm/msr-index.h
arch/x86/kernel/cpu/amd.c
arch/x86/kernel/cpu/common.c

index 79b1d009e34e4fce073ece13cd0c99c2f169dfa1..19a0b4005ffa869265a59cbffba08c243fb595e3 100644 (file)
@@ -5,6 +5,7 @@
 #include <asm/cpu.h>
 #include <linux/earlycpio.h>
 #include <linux/initrd.h>
+#include <asm/microcode_amd.h>
 
 struct ucode_patch {
        struct list_head plist;
index e6662adf3af4d40356fa343fb7111cc77141bc32..9675c621c1ca44ccda7a6713f96882418bf48934 100644 (file)
@@ -48,11 +48,13 @@ extern void __init load_ucode_amd_bsp(unsigned int family);
 extern void load_ucode_amd_ap(unsigned int family);
 extern int __init save_microcode_in_initrd_amd(unsigned int family);
 void reload_ucode_amd(unsigned int cpu);
+extern void amd_check_microcode(void);
 #else
 static inline void __init load_ucode_amd_bsp(unsigned int family) {}
 static inline void load_ucode_amd_ap(unsigned int family) {}
 static inline int __init
 save_microcode_in_initrd_amd(unsigned int family) { return -EINVAL; }
 static inline void reload_ucode_amd(unsigned int cpu) {}
+static inline void amd_check_microcode(void) {}
 #endif
 #endif /* _ASM_X86_MICROCODE_AMD_H */
index 117e4e977b55d67b1b288bbc098736aca7d115ae..846067e1ee8bb527eebef01d12d7f9c0da1717a3 100644 (file)
 #define MSR_AMD64_DE_CFG               0xc0011029
 #define MSR_AMD64_DE_CFG_LFENCE_SERIALIZE_BIT   1
 #define MSR_AMD64_DE_CFG_LFENCE_SERIALIZE      BIT_ULL(MSR_AMD64_DE_CFG_LFENCE_SERIALIZE_BIT)
+#define MSR_AMD64_DE_CFG_ZEN2_FP_BACKUP_FIX_BIT 9
 
 #define MSR_AMD64_BU_CFG2              0xc001102a
 #define MSR_AMD64_IBSFETCHCTL          0xc0011030
index 16b05029e06881430b6630df0cdccea7d144c447..7f4eb8b027cc84a5856dd8d337c9b133ba227ab9 100644 (file)
@@ -70,6 +70,11 @@ static const int amd_erratum_383[] =
 static const int amd_erratum_1054[] =
        AMD_LEGACY_ERRATUM(AMD_MODEL_RANGE(0x17, 0, 0, 0x2f, 0xf));
 
+static const int amd_zenbleed[] =
+       AMD_LEGACY_ERRATUM(AMD_MODEL_RANGE(0x17, 0x30, 0x0, 0x4f, 0xf),
+                          AMD_MODEL_RANGE(0x17, 0x60, 0x0, 0x7f, 0xf),
+                          AMD_MODEL_RANGE(0x17, 0xa0, 0x0, 0xaf, 0xf));
+
 static bool cpu_has_amd_erratum(struct cpuinfo_x86 *cpu, const int *erratum)
 {
        int osvw_id = *erratum++;
@@ -978,6 +983,47 @@ static void init_amd_zn(struct cpuinfo_x86 *c)
        }
 }
 
+static bool cpu_has_zenbleed_microcode(void)
+{
+       u32 good_rev = 0;
+
+       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:
+               return false;
+               break;
+       }
+
+       if (boot_cpu_data.microcode < good_rev)
+               return false;
+
+       return true;
+}
+
+static void zenbleed_check(struct cpuinfo_x86 *c)
+{
+       if (!cpu_has_amd_erratum(c, amd_zenbleed))
+               return;
+
+       if (cpu_has(c, X86_FEATURE_HYPERVISOR))
+               return;
+
+       if (!cpu_has(c, X86_FEATURE_AVX))
+               return;
+
+       if (!cpu_has_zenbleed_microcode()) {
+               pr_notice_once("Zenbleed: please update your microcode for the most optimal fix\n");
+               msr_set_bit(MSR_AMD64_DE_CFG, MSR_AMD64_DE_CFG_ZEN2_FP_BACKUP_FIX_BIT);
+       } else {
+               msr_clear_bit(MSR_AMD64_DE_CFG, MSR_AMD64_DE_CFG_ZEN2_FP_BACKUP_FIX_BIT);
+       }
+}
+
 static void init_amd(struct cpuinfo_x86 *c)
 {
        early_init_amd(c);
@@ -1067,6 +1113,8 @@ static void init_amd(struct cpuinfo_x86 *c)
                msr_set_bit(MSR_K7_HWCR, MSR_K7_HWCR_IRPERF_EN_BIT);
 
        check_null_seg_clears_base(c);
+
+       zenbleed_check(c);
 }
 
 #ifdef CONFIG_X86_32
@@ -1196,3 +1244,15 @@ u32 amd_get_highest_perf(void)
        return 255;
 }
 EXPORT_SYMBOL_GPL(amd_get_highest_perf);
+
+static void zenbleed_check_cpu(void *unused)
+{
+       struct cpuinfo_x86 *c = &cpu_data(smp_processor_id());
+
+       zenbleed_check(c);
+}
+
+void amd_check_microcode(void)
+{
+       on_each_cpu(zenbleed_check_cpu, NULL, 1);
+}
index c34bdba57993aa11bcc3fc89e2e03f747e7967c1..d298d70f74ce66b28b57b6c8b24b7e409f9301d9 100644 (file)
@@ -2346,6 +2346,8 @@ void microcode_check(struct cpuinfo_x86 *prev_info)
 
        perf_check_microcode();
 
+       amd_check_microcode();
+
        store_cpu_caps(&curr_info);
 
        if (!memcmp(&prev_info->x86_capability, &curr_info.x86_capability,