Skip to content

Commit

Permalink
riscv: Add ghostwrite vulnerability
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Charlie Jenkins authored and Palmer Dabbelt committed Jan 18, 2025
1 parent c384c5d commit 4bf9706
Show file tree
Hide file tree
Showing 9 changed files with 138 additions and 2 deletions.
11 changes: 11 additions & 0 deletions arch/riscv/Kconfig.errata
Original file line number Diff line number Diff line change
Expand Up @@ -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"
28 changes: 28 additions & 0 deletions arch/riscv/errata/thead/errata.c
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -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)
{
Expand All @@ -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;
}

Expand Down
22 changes: 22 additions & 0 deletions arch/riscv/include/asm/bugs.h
Original file line number Diff line number Diff line change
@@ -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 */
3 changes: 2 additions & 1 deletion arch/riscv/include/asm/errata_list.h
Original file line number Diff line number Diff line change
Expand Up @@ -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__
Expand Down
2 changes: 2 additions & 0 deletions arch/riscv/kernel/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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
60 changes: 60 additions & 0 deletions arch/riscv/kernel/bugs.c
Original file line number Diff line number Diff line change
@@ -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");
}
}
10 changes: 9 additions & 1 deletion arch/riscv/kernel/cpufeature.c
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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();
}
Expand Down
3 changes: 3 additions & 0 deletions drivers/base/cpu.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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,
Expand All @@ -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
};

Expand Down
1 change: 1 addition & 0 deletions include/linux/cpu.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down

0 comments on commit 4bf9706

Please sign in to comment.