Skip to content

Commit d405b9c

Browse files
pa1guptaSasha Levin
authored andcommitted
x86/rfds: Mitigate Register File Data Sampling (RFDS)
commit 8076fcd upstream. RFDS is a CPU vulnerability that may allow userspace to infer kernel stale data previously used in floating point registers, vector registers and integer registers. RFDS only affects certain Intel Atom processors. Intel released a microcode update that uses VERW instruction to clear the affected CPU buffers. Unlike MDS, none of the affected cores support SMT. Add RFDS bug infrastructure and enable the VERW based mitigation by default, that clears the affected buffers just before exiting to userspace. Also add sysfs reporting and cmdline parameter "reg_file_data_sampling" to control the mitigation. For details see: Documentation/admin-guide/hw-vuln/reg-file-data-sampling.rst Signed-off-by: Pawan Gupta <[email protected]> Signed-off-by: Dave Hansen <[email protected]> Reviewed-by: Thomas Gleixner <[email protected]> Acked-by: Josh Poimboeuf <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 29476fa commit d405b9c

File tree

9 files changed

+162
-6
lines changed

9 files changed

+162
-6
lines changed

Documentation/ABI/testing/sysfs-devices-system-cpu

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -519,6 +519,7 @@ What: /sys/devices/system/cpu/vulnerabilities
519519
/sys/devices/system/cpu/vulnerabilities/mds
520520
/sys/devices/system/cpu/vulnerabilities/meltdown
521521
/sys/devices/system/cpu/vulnerabilities/mmio_stale_data
522+
/sys/devices/system/cpu/vulnerabilities/reg_file_data_sampling
522523
/sys/devices/system/cpu/vulnerabilities/retbleed
523524
/sys/devices/system/cpu/vulnerabilities/spec_store_bypass
524525
/sys/devices/system/cpu/vulnerabilities/spectre_v1

Documentation/admin-guide/kernel-parameters.txt

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1107,6 +1107,26 @@
11071107
The filter can be disabled or changed to another
11081108
driver later using sysfs.
11091109

1110+
reg_file_data_sampling=
1111+
[X86] Controls mitigation for Register File Data
1112+
Sampling (RFDS) vulnerability. RFDS is a CPU
1113+
vulnerability which may allow userspace to infer
1114+
kernel data values previously stored in floating point
1115+
registers, vector registers, or integer registers.
1116+
RFDS only affects Intel Atom processors.
1117+
1118+
on: Turns ON the mitigation.
1119+
off: Turns OFF the mitigation.
1120+
1121+
This parameter overrides the compile time default set
1122+
by CONFIG_MITIGATION_RFDS. Mitigation cannot be
1123+
disabled when other VERW based mitigations (like MDS)
1124+
are enabled. In order to disable RFDS mitigation all
1125+
VERW based mitigations need to be disabled.
1126+
1127+
For details see:
1128+
Documentation/admin-guide/hw-vuln/reg-file-data-sampling.rst
1129+
11101130
driver_async_probe= [KNL]
11111131
List of driver names to be probed asynchronously. *
11121132
matches with all driver names. If * is specified, the
@@ -3262,6 +3282,7 @@
32623282
nospectre_bhb [ARM64]
32633283
nospectre_v1 [X86,PPC]
32643284
nospectre_v2 [X86,PPC,S390,ARM64]
3285+
reg_file_data_sampling=off [X86]
32653286
retbleed=off [X86]
32663287
spec_store_bypass_disable=off [X86,PPC]
32673288
spectre_v2_user=off [X86]

arch/x86/Kconfig

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2565,6 +2565,17 @@ config GDS_FORCE_MITIGATION
25652565

25662566
If in doubt, say N.
25672567

2568+
config MITIGATION_RFDS
2569+
bool "RFDS Mitigation"
2570+
depends on CPU_SUP_INTEL
2571+
default y
2572+
help
2573+
Enable mitigation for Register File Data Sampling (RFDS) by default.
2574+
RFDS is a hardware vulnerability which affects Intel Atom CPUs. It
2575+
allows unprivileged speculative access to stale data previously
2576+
stored in floating point, vector and integer registers.
2577+
See also <file:Documentation/admin-guide/hw-vuln/reg-file-data-sampling.rst>
2578+
25682579
endif
25692580

25702581
config ARCH_HAS_ADD_PAGES

arch/x86/include/asm/cpufeatures.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -477,4 +477,5 @@
477477
/* BUG word 2 */
478478
#define X86_BUG_SRSO X86_BUG(1*32 + 0) /* AMD SRSO bug */
479479
#define X86_BUG_DIV0 X86_BUG(1*32 + 1) /* AMD DIV0 speculation bug */
480+
#define X86_BUG_RFDS X86_BUG(1*32 + 2) /* CPU is vulnerable to Register File Data Sampling */
480481
#endif /* _ASM_X86_CPUFEATURES_H */

arch/x86/include/asm/msr-index.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,14 @@
168168
* CPU is not vulnerable to Gather
169169
* Data Sampling (GDS).
170170
*/
171+
#define ARCH_CAP_RFDS_NO BIT(27) /*
172+
* Not susceptible to Register
173+
* File Data Sampling.
174+
*/
175+
#define ARCH_CAP_RFDS_CLEAR BIT(28) /*
176+
* VERW clears CPU Register
177+
* File.
178+
*/
171179

172180
#define ARCH_CAP_XAPIC_DISABLE BIT(21) /*
173181
* IA32_XAPIC_DISABLE_STATUS MSR

arch/x86/kernel/cpu/bugs.c

Lines changed: 75 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -479,6 +479,57 @@ static int __init mmio_stale_data_parse_cmdline(char *str)
479479
}
480480
early_param("mmio_stale_data", mmio_stale_data_parse_cmdline);
481481

482+
#undef pr_fmt
483+
#define pr_fmt(fmt) "Register File Data Sampling: " fmt
484+
485+
enum rfds_mitigations {
486+
RFDS_MITIGATION_OFF,
487+
RFDS_MITIGATION_VERW,
488+
RFDS_MITIGATION_UCODE_NEEDED,
489+
};
490+
491+
/* Default mitigation for Register File Data Sampling */
492+
static enum rfds_mitigations rfds_mitigation __ro_after_init =
493+
IS_ENABLED(CONFIG_MITIGATION_RFDS) ? RFDS_MITIGATION_VERW : RFDS_MITIGATION_OFF;
494+
495+
static const char * const rfds_strings[] = {
496+
[RFDS_MITIGATION_OFF] = "Vulnerable",
497+
[RFDS_MITIGATION_VERW] = "Mitigation: Clear Register File",
498+
[RFDS_MITIGATION_UCODE_NEEDED] = "Vulnerable: No microcode",
499+
};
500+
501+
static void __init rfds_select_mitigation(void)
502+
{
503+
if (!boot_cpu_has_bug(X86_BUG_RFDS) || cpu_mitigations_off()) {
504+
rfds_mitigation = RFDS_MITIGATION_OFF;
505+
return;
506+
}
507+
if (rfds_mitigation == RFDS_MITIGATION_OFF)
508+
return;
509+
510+
if (x86_read_arch_cap_msr() & ARCH_CAP_RFDS_CLEAR)
511+
setup_force_cpu_cap(X86_FEATURE_CLEAR_CPU_BUF);
512+
else
513+
rfds_mitigation = RFDS_MITIGATION_UCODE_NEEDED;
514+
}
515+
516+
static __init int rfds_parse_cmdline(char *str)
517+
{
518+
if (!str)
519+
return -EINVAL;
520+
521+
if (!boot_cpu_has_bug(X86_BUG_RFDS))
522+
return 0;
523+
524+
if (!strcmp(str, "off"))
525+
rfds_mitigation = RFDS_MITIGATION_OFF;
526+
else if (!strcmp(str, "on"))
527+
rfds_mitigation = RFDS_MITIGATION_VERW;
528+
529+
return 0;
530+
}
531+
early_param("reg_file_data_sampling", rfds_parse_cmdline);
532+
482533
#undef pr_fmt
483534
#define pr_fmt(fmt) "" fmt
484535

@@ -512,6 +563,11 @@ static void __init md_clear_update_mitigation(void)
512563
mmio_mitigation = MMIO_MITIGATION_VERW;
513564
mmio_select_mitigation();
514565
}
566+
if (rfds_mitigation == RFDS_MITIGATION_OFF &&
567+
boot_cpu_has_bug(X86_BUG_RFDS)) {
568+
rfds_mitigation = RFDS_MITIGATION_VERW;
569+
rfds_select_mitigation();
570+
}
515571
out:
516572
if (boot_cpu_has_bug(X86_BUG_MDS))
517573
pr_info("MDS: %s\n", mds_strings[mds_mitigation]);
@@ -521,18 +577,21 @@ static void __init md_clear_update_mitigation(void)
521577
pr_info("MMIO Stale Data: %s\n", mmio_strings[mmio_mitigation]);
522578
else if (boot_cpu_has_bug(X86_BUG_MMIO_UNKNOWN))
523579
pr_info("MMIO Stale Data: Unknown: No mitigations\n");
580+
if (boot_cpu_has_bug(X86_BUG_RFDS))
581+
pr_info("Register File Data Sampling: %s\n", rfds_strings[rfds_mitigation]);
524582
}
525583

526584
static void __init md_clear_select_mitigation(void)
527585
{
528586
mds_select_mitigation();
529587
taa_select_mitigation();
530588
mmio_select_mitigation();
589+
rfds_select_mitigation();
531590

532591
/*
533-
* As MDS, TAA and MMIO Stale Data mitigations are inter-related, update
534-
* and print their mitigation after MDS, TAA and MMIO Stale Data
535-
* mitigation selection is done.
592+
* As these mitigations are inter-related and rely on VERW instruction
593+
* to clear the microarchitural buffers, update and print their status
594+
* after mitigation selection is done for each of these vulnerabilities.
536595
*/
537596
md_clear_update_mitigation();
538597
}
@@ -2596,6 +2655,11 @@ static ssize_t mmio_stale_data_show_state(char *buf)
25962655
sched_smt_active() ? "vulnerable" : "disabled");
25972656
}
25982657

2658+
static ssize_t rfds_show_state(char *buf)
2659+
{
2660+
return sysfs_emit(buf, "%s\n", rfds_strings[rfds_mitigation]);
2661+
}
2662+
25992663
static char *stibp_state(void)
26002664
{
26012665
if (spectre_v2_in_eibrs_mode(spectre_v2_enabled))
@@ -2757,6 +2821,9 @@ static ssize_t cpu_show_common(struct device *dev, struct device_attribute *attr
27572821
case X86_BUG_SRSO:
27582822
return srso_show_state(buf);
27592823

2824+
case X86_BUG_RFDS:
2825+
return rfds_show_state(buf);
2826+
27602827
default:
27612828
break;
27622829
}
@@ -2831,4 +2898,9 @@ ssize_t cpu_show_spec_rstack_overflow(struct device *dev, struct device_attribut
28312898
{
28322899
return cpu_show_common(dev, attr, buf, X86_BUG_SRSO);
28332900
}
2901+
2902+
ssize_t cpu_show_reg_file_data_sampling(struct device *dev, struct device_attribute *attr, char *buf)
2903+
{
2904+
return cpu_show_common(dev, attr, buf, X86_BUG_RFDS);
2905+
}
28342906
#endif

arch/x86/kernel/cpu/common.c

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1248,6 +1248,8 @@ static const __initconst struct x86_cpu_id cpu_vuln_whitelist[] = {
12481248
#define SRSO BIT(5)
12491249
/* CPU is affected by GDS */
12501250
#define GDS BIT(6)
1251+
/* CPU is affected by Register File Data Sampling */
1252+
#define RFDS BIT(7)
12511253

12521254
static const struct x86_cpu_id cpu_vuln_blacklist[] __initconst = {
12531255
VULNBL_INTEL_STEPPINGS(IVYBRIDGE, X86_STEPPING_ANY, SRBDS),
@@ -1275,9 +1277,18 @@ static const struct x86_cpu_id cpu_vuln_blacklist[] __initconst = {
12751277
VULNBL_INTEL_STEPPINGS(TIGERLAKE, X86_STEPPING_ANY, GDS),
12761278
VULNBL_INTEL_STEPPINGS(LAKEFIELD, X86_STEPPING_ANY, MMIO | MMIO_SBDS | RETBLEED),
12771279
VULNBL_INTEL_STEPPINGS(ROCKETLAKE, X86_STEPPING_ANY, MMIO | RETBLEED | GDS),
1278-
VULNBL_INTEL_STEPPINGS(ATOM_TREMONT, X86_STEPPING_ANY, MMIO | MMIO_SBDS),
1279-
VULNBL_INTEL_STEPPINGS(ATOM_TREMONT_D, X86_STEPPING_ANY, MMIO),
1280-
VULNBL_INTEL_STEPPINGS(ATOM_TREMONT_L, X86_STEPPING_ANY, MMIO | MMIO_SBDS),
1280+
VULNBL_INTEL_STEPPINGS(ALDERLAKE, X86_STEPPING_ANY, RFDS),
1281+
VULNBL_INTEL_STEPPINGS(ALDERLAKE_L, X86_STEPPING_ANY, RFDS),
1282+
VULNBL_INTEL_STEPPINGS(RAPTORLAKE, X86_STEPPING_ANY, RFDS),
1283+
VULNBL_INTEL_STEPPINGS(RAPTORLAKE_P, X86_STEPPING_ANY, RFDS),
1284+
VULNBL_INTEL_STEPPINGS(RAPTORLAKE_S, X86_STEPPING_ANY, RFDS),
1285+
VULNBL_INTEL_STEPPINGS(ALDERLAKE_N, X86_STEPPING_ANY, RFDS),
1286+
VULNBL_INTEL_STEPPINGS(ATOM_TREMONT, X86_STEPPING_ANY, MMIO | MMIO_SBDS | RFDS),
1287+
VULNBL_INTEL_STEPPINGS(ATOM_TREMONT_D, X86_STEPPING_ANY, MMIO | RFDS),
1288+
VULNBL_INTEL_STEPPINGS(ATOM_TREMONT_L, X86_STEPPING_ANY, MMIO | MMIO_SBDS | RFDS),
1289+
VULNBL_INTEL_STEPPINGS(ATOM_GOLDMONT, X86_STEPPING_ANY, RFDS),
1290+
VULNBL_INTEL_STEPPINGS(ATOM_GOLDMONT_D, X86_STEPPING_ANY, RFDS),
1291+
VULNBL_INTEL_STEPPINGS(ATOM_GOLDMONT_PLUS, X86_STEPPING_ANY, RFDS),
12811292

12821293
VULNBL_AMD(0x15, RETBLEED),
12831294
VULNBL_AMD(0x16, RETBLEED),
@@ -1311,6 +1322,24 @@ static bool arch_cap_mmio_immune(u64 ia32_cap)
13111322
ia32_cap & ARCH_CAP_SBDR_SSDP_NO);
13121323
}
13131324

1325+
static bool __init vulnerable_to_rfds(u64 ia32_cap)
1326+
{
1327+
/* The "immunity" bit trumps everything else: */
1328+
if (ia32_cap & ARCH_CAP_RFDS_NO)
1329+
return false;
1330+
1331+
/*
1332+
* VMMs set ARCH_CAP_RFDS_CLEAR for processors not in the blacklist to
1333+
* indicate that mitigation is needed because guest is running on a
1334+
* vulnerable hardware or may migrate to such hardware:
1335+
*/
1336+
if (ia32_cap & ARCH_CAP_RFDS_CLEAR)
1337+
return true;
1338+
1339+
/* Only consult the blacklist when there is no enumeration: */
1340+
return cpu_matches(cpu_vuln_blacklist, RFDS);
1341+
}
1342+
13141343
static void __init cpu_set_bug_bits(struct cpuinfo_x86 *c)
13151344
{
13161345
u64 ia32_cap = x86_read_arch_cap_msr();
@@ -1419,6 +1448,9 @@ static void __init cpu_set_bug_bits(struct cpuinfo_x86 *c)
14191448
setup_force_cpu_bug(X86_BUG_SRSO);
14201449
}
14211450

1451+
if (vulnerable_to_rfds(ia32_cap))
1452+
setup_force_cpu_bug(X86_BUG_RFDS);
1453+
14221454
if (cpu_matches(cpu_vuln_whitelist, NO_MELTDOWN))
14231455
return;
14241456

drivers/base/cpu.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -589,6 +589,12 @@ ssize_t __weak cpu_show_spec_rstack_overflow(struct device *dev,
589589
return sysfs_emit(buf, "Not affected\n");
590590
}
591591

592+
ssize_t __weak cpu_show_reg_file_data_sampling(struct device *dev,
593+
struct device_attribute *attr, char *buf)
594+
{
595+
return sysfs_emit(buf, "Not affected\n");
596+
}
597+
592598
static DEVICE_ATTR(meltdown, 0444, cpu_show_meltdown, NULL);
593599
static DEVICE_ATTR(spectre_v1, 0444, cpu_show_spectre_v1, NULL);
594600
static DEVICE_ATTR(spectre_v2, 0444, cpu_show_spectre_v2, NULL);
@@ -602,6 +608,7 @@ static DEVICE_ATTR(mmio_stale_data, 0444, cpu_show_mmio_stale_data, NULL);
602608
static DEVICE_ATTR(retbleed, 0444, cpu_show_retbleed, NULL);
603609
static DEVICE_ATTR(gather_data_sampling, 0444, cpu_show_gds, NULL);
604610
static DEVICE_ATTR(spec_rstack_overflow, 0444, cpu_show_spec_rstack_overflow, NULL);
611+
static DEVICE_ATTR(reg_file_data_sampling, 0444, cpu_show_reg_file_data_sampling, NULL);
605612

606613
static struct attribute *cpu_root_vulnerabilities_attrs[] = {
607614
&dev_attr_meltdown.attr,
@@ -617,6 +624,7 @@ static struct attribute *cpu_root_vulnerabilities_attrs[] = {
617624
&dev_attr_retbleed.attr,
618625
&dev_attr_gather_data_sampling.attr,
619626
&dev_attr_spec_rstack_overflow.attr,
627+
&dev_attr_reg_file_data_sampling.attr,
620628
NULL
621629
};
622630

include/linux/cpu.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,8 @@ extern ssize_t cpu_show_spec_rstack_overflow(struct device *dev,
7474
struct device_attribute *attr, char *buf);
7575
extern ssize_t cpu_show_gds(struct device *dev,
7676
struct device_attribute *attr, char *buf);
77+
extern ssize_t cpu_show_reg_file_data_sampling(struct device *dev,
78+
struct device_attribute *attr, char *buf);
7779

7880
extern __printf(4, 5)
7981
struct device *cpu_device_create(struct device *parent, void *drvdata,

0 commit comments

Comments
 (0)