]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
riscv: Add ghostwrite vulnerability
authorCharlie Jenkins <charlie@rivosinc.com>
Thu, 14 Nov 2024 02:21:20 +0000 (18:21 -0800)
committerPalmer Dabbelt <palmer@rivosinc.com>
Sat, 18 Jan 2025 20:33:39 +0000 (12:33 -0800)
Follow the patterns of the other architectures that use
GENERIC_CPU_VULNERABILITIES for riscv to introduce the ghostwrite
vulnerability and mitigation. The mitigation is to disable all vector
which is accomplished by clearing the bit from the cpufeature field.

Ghostwrite only affects thead c9xx CPUs that impelment xtheadvector, so
the vulerability will only be mitigated on these CPUs.

Signed-off-by: Charlie Jenkins <charlie@rivosinc.com>
Tested-by: Yangyu Chen <cyy@cyyself.name>
Link: https://lore.kernel.org/r/20241113-xtheadvector-v11-14-236c22791ef9@rivosinc.com
Signed-off-by: Palmer Dabbelt <palmer@rivosinc.com>
arch/riscv/Kconfig.errata
arch/riscv/errata/thead/errata.c
arch/riscv/include/asm/bugs.h [new file with mode: 0644]
arch/riscv/include/asm/errata_list.h
arch/riscv/kernel/Makefile
arch/riscv/kernel/bugs.c [new file with mode: 0644]
arch/riscv/kernel/cpufeature.c
drivers/base/cpu.c
include/linux/cpu.h

index 2acc7d876e1fb6aa5dc14ad3c3150f587ba1edea..e318119d570de0acc0850a2e1a2505ecb71bea08 100644 (file)
@@ -119,4 +119,15 @@ config ERRATA_THEAD_PMU
 
          If you don't know what to do here, say "Y".
 
+config ERRATA_THEAD_GHOSTWRITE
+       bool "Apply T-Head Ghostwrite errata"
+       depends on ERRATA_THEAD && RISCV_ISA_XTHEADVECTOR
+       default y
+       help
+         The T-Head C9xx cores have a vulnerability in the xtheadvector
+         instruction set. When this errata is enabled, the CPUs will be probed
+         to determine if they are vulnerable and disable xtheadvector.
+
+         If you don't know what to do here, say "Y".
+
 endmenu # "CPU errata selection"
index f5120e07c3182642026e8e0c7083e054ba3fd9de..5cc008ab41a87a21215dbb827de70aa5d29fee4d 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/string.h>
 #include <linux/uaccess.h>
 #include <asm/alternative.h>
+#include <asm/bugs.h>
 #include <asm/cacheflush.h>
 #include <asm/cpufeature.h>
 #include <asm/dma-noncoherent.h>
@@ -142,6 +143,31 @@ static bool errata_probe_pmu(unsigned int stage,
        return true;
 }
 
+static bool errata_probe_ghostwrite(unsigned int stage,
+                                   unsigned long arch_id, unsigned long impid)
+{
+       if (!IS_ENABLED(CONFIG_ERRATA_THEAD_GHOSTWRITE))
+               return false;
+
+       /*
+        * target-c9xx cores report arch_id and impid as 0
+        *
+        * While ghostwrite may not affect all c9xx cores that implement
+        * xtheadvector, there is no futher granularity than c9xx. Assume
+        * vulnerable for this entire class of processors when xtheadvector is
+        * enabled.
+        */
+       if (arch_id != 0 || impid != 0)
+               return false;
+
+       if (stage != RISCV_ALTERNATIVES_EARLY_BOOT)
+               return false;
+
+       ghostwrite_set_vulnerable();
+
+       return true;
+}
+
 static u32 thead_errata_probe(unsigned int stage,
                              unsigned long archid, unsigned long impid)
 {
@@ -155,6 +181,8 @@ static u32 thead_errata_probe(unsigned int stage,
        if (errata_probe_pmu(stage, archid, impid))
                cpu_req_errata |= BIT(ERRATA_THEAD_PMU);
 
+       errata_probe_ghostwrite(stage, archid, impid);
+
        return cpu_req_errata;
 }
 
diff --git a/arch/riscv/include/asm/bugs.h b/arch/riscv/include/asm/bugs.h
new file mode 100644 (file)
index 0000000..17ca0a9
--- /dev/null
@@ -0,0 +1,22 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Interface for managing mitigations for riscv vulnerabilities.
+ *
+ * Copyright (C) 2024 Rivos Inc.
+ */
+
+#ifndef __ASM_BUGS_H
+#define __ASM_BUGS_H
+
+/* Watch out, ordering is important here. */
+enum mitigation_state {
+       UNAFFECTED,
+       MITIGATED,
+       VULNERABLE,
+};
+
+void ghostwrite_set_vulnerable(void);
+bool ghostwrite_enable_mitigation(void);
+enum mitigation_state ghostwrite_get_state(void);
+
+#endif /* __ASM_BUGS_H */
index 7c8a71a526a3079018fc41763c06e6ef20c50f4a..6e426ed7919a4acd997b60b723c0d5cfddb4cff6 100644 (file)
@@ -25,7 +25,8 @@
 #ifdef CONFIG_ERRATA_THEAD
 #define        ERRATA_THEAD_MAE 0
 #define        ERRATA_THEAD_PMU 1
-#define        ERRATA_THEAD_NUMBER 2
+#define        ERRATA_THEAD_GHOSTWRITE 2
+#define        ERRATA_THEAD_NUMBER 3
 #endif
 
 #ifdef __ASSEMBLY__
index 30db92672ada54048c5f62296ffc7168c78d32db..d73f04c6c5637e42563995e085074859f46853f6 100644 (file)
@@ -118,3 +118,5 @@ obj-$(CONFIG_COMPAT)                += compat_vdso/
 obj-$(CONFIG_64BIT)            += pi/
 obj-$(CONFIG_ACPI)             += acpi.o
 obj-$(CONFIG_ACPI_NUMA)        += acpi_numa.o
+
+obj-$(CONFIG_GENERIC_CPU_VULNERABILITIES) += bugs.o
diff --git a/arch/riscv/kernel/bugs.c b/arch/riscv/kernel/bugs.c
new file mode 100644 (file)
index 0000000..3655fe7
--- /dev/null
@@ -0,0 +1,60 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2024 Rivos Inc.
+ */
+
+#include <linux/cpu.h>
+#include <linux/device.h>
+#include <linux/sprintf.h>
+
+#include <asm/bugs.h>
+#include <asm/vendor_extensions/thead.h>
+
+static enum mitigation_state ghostwrite_state;
+
+void ghostwrite_set_vulnerable(void)
+{
+       ghostwrite_state = VULNERABLE;
+}
+
+/*
+ * Vendor extension alternatives will use the value set at the time of boot
+ * alternative patching, thus this must be called before boot alternatives are
+ * patched (and after extension probing) to be effective.
+ *
+ * Returns true if mitgated, false otherwise.
+ */
+bool ghostwrite_enable_mitigation(void)
+{
+       if (IS_ENABLED(CONFIG_RISCV_ISA_XTHEADVECTOR) &&
+           ghostwrite_state == VULNERABLE && !cpu_mitigations_off()) {
+               disable_xtheadvector();
+               ghostwrite_state = MITIGATED;
+               return true;
+       }
+
+       return false;
+}
+
+enum mitigation_state ghostwrite_get_state(void)
+{
+       return ghostwrite_state;
+}
+
+ssize_t cpu_show_ghostwrite(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       if (IS_ENABLED(CONFIG_RISCV_ISA_XTHEADVECTOR)) {
+               switch (ghostwrite_state) {
+               case UNAFFECTED:
+                       return sprintf(buf, "Not affected\n");
+               case MITIGATED:
+                       return sprintf(buf, "Mitigation: xtheadvector disabled\n");
+               case VULNERABLE:
+                       fallthrough;
+               default:
+                       return sprintf(buf, "Vulnerable\n");
+               }
+       } else {
+               return sprintf(buf, "Not affected\n");
+       }
+}
index ba6976132638c8ac8d4d2b7b38aa356466333b72..35670c96b3830d441793d71c6cdadef22c484f82 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/of.h>
 #include <asm/acpi.h>
 #include <asm/alternative.h>
+#include <asm/bugs.h>
 #include <asm/cacheflush.h>
 #include <asm/cpufeature.h>
 #include <asm/hwcap.h>
@@ -824,6 +825,7 @@ static int has_thead_homogeneous_vlenb(void)
 static int __init riscv_fill_hwcap_from_ext_list(unsigned long *isa2hwcap)
 {
        unsigned int cpu;
+       bool mitigated;
 
        for_each_possible_cpu(cpu) {
                unsigned long this_hwcap = 0;
@@ -874,7 +876,13 @@ static int __init riscv_fill_hwcap_from_ext_list(unsigned long *isa2hwcap)
                riscv_fill_vendor_ext_list(cpu);
        }
 
-       if (has_xtheadvector_no_alternatives() && has_thead_homogeneous_vlenb() < 0) {
+       /*
+        * Execute ghostwrite mitigation immediately after detecting extensions
+        * to disable xtheadvector if necessary.
+        */
+       mitigated = ghostwrite_enable_mitigation();
+
+       if (!mitigated && has_xtheadvector_no_alternatives() && has_thead_homogeneous_vlenb() < 0) {
                pr_warn("Unsupported heterogeneous vlenb detected, vector extension disabled.\n");
                disable_xtheadvector();
        }
index fdaa24bb641a00ebd0b526db3af7d2eff44d04c9..a7e5118498758ef05cc98cd87655dc0b64110193 100644 (file)
@@ -599,6 +599,7 @@ CPU_SHOW_VULN_FALLBACK(retbleed);
 CPU_SHOW_VULN_FALLBACK(spec_rstack_overflow);
 CPU_SHOW_VULN_FALLBACK(gds);
 CPU_SHOW_VULN_FALLBACK(reg_file_data_sampling);
+CPU_SHOW_VULN_FALLBACK(ghostwrite);
 
 static DEVICE_ATTR(meltdown, 0444, cpu_show_meltdown, NULL);
 static DEVICE_ATTR(spectre_v1, 0444, cpu_show_spectre_v1, NULL);
@@ -614,6 +615,7 @@ static DEVICE_ATTR(retbleed, 0444, cpu_show_retbleed, NULL);
 static DEVICE_ATTR(spec_rstack_overflow, 0444, cpu_show_spec_rstack_overflow, NULL);
 static DEVICE_ATTR(gather_data_sampling, 0444, cpu_show_gds, NULL);
 static DEVICE_ATTR(reg_file_data_sampling, 0444, cpu_show_reg_file_data_sampling, NULL);
+static DEVICE_ATTR(ghostwrite, 0444, cpu_show_ghostwrite, NULL);
 
 static struct attribute *cpu_root_vulnerabilities_attrs[] = {
        &dev_attr_meltdown.attr,
@@ -630,6 +632,7 @@ static struct attribute *cpu_root_vulnerabilities_attrs[] = {
        &dev_attr_spec_rstack_overflow.attr,
        &dev_attr_gather_data_sampling.attr,
        &dev_attr_reg_file_data_sampling.attr,
+       &dev_attr_ghostwrite.attr,
        NULL
 };
 
index bdcec173244522d56b428265f3af0b1b0d0c32ef..6a0a8f1c7c90358f9e50ada3a1efd82a1506eacf 100644 (file)
@@ -77,6 +77,7 @@ extern ssize_t cpu_show_gds(struct device *dev,
                            struct device_attribute *attr, char *buf);
 extern ssize_t cpu_show_reg_file_data_sampling(struct device *dev,
                                               struct device_attribute *attr, char *buf);
+extern ssize_t cpu_show_ghostwrite(struct device *dev, struct device_attribute *attr, char *buf);
 
 extern __printf(4, 5)
 struct device *cpu_device_create(struct device *parent, void *drvdata,