Skip to content

Commit 8076fcd

Browse files
pa1guptahansendc
authored andcommitted
x86/rfds: Mitigate Register File Data Sampling (RFDS)
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 <pawan.kumar.gupta@linux.intel.com> Signed-off-by: Dave Hansen <dave.hansen@linux.intel.com> Reviewed-by: Thomas Gleixner <tglx@linutronix.de> Acked-by: Josh Poimboeuf <jpoimboe@kernel.org>
1 parent 4e42765 commit 8076fcd

File tree

9 files changed

+157
-6
lines changed

9 files changed

+157
-6
lines changed

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -516,6 +516,7 @@ What: /sys/devices/system/cpu/vulnerabilities
516516
/sys/devices/system/cpu/vulnerabilities/mds
517517
/sys/devices/system/cpu/vulnerabilities/meltdown
518518
/sys/devices/system/cpu/vulnerabilities/mmio_stale_data
519+
/sys/devices/system/cpu/vulnerabilities/reg_file_data_sampling
519520
/sys/devices/system/cpu/vulnerabilities/retbleed
520521
/sys/devices/system/cpu/vulnerabilities/spec_store_bypass
521522
/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
@@ -1150,6 +1150,26 @@
11501150
The filter can be disabled or changed to another
11511151
driver later using sysfs.
11521152

1153+
reg_file_data_sampling=
1154+
[X86] Controls mitigation for Register File Data
1155+
Sampling (RFDS) vulnerability. RFDS is a CPU
1156+
vulnerability which may allow userspace to infer
1157+
kernel data values previously stored in floating point
1158+
registers, vector registers, or integer registers.
1159+
RFDS only affects Intel Atom processors.
1160+
1161+
on: Turns ON the mitigation.
1162+
off: Turns OFF the mitigation.
1163+
1164+
This parameter overrides the compile time default set
1165+
by CONFIG_MITIGATION_RFDS. Mitigation cannot be
1166+
disabled when other VERW based mitigations (like MDS)
1167+
are enabled. In order to disable RFDS mitigation all
1168+
VERW based mitigations need to be disabled.
1169+
1170+
For details see:
1171+
Documentation/admin-guide/hw-vuln/reg-file-data-sampling.rst
1172+
11531173
driver_async_probe= [KNL]
11541174
List of driver names to be probed asynchronously. *
11551175
matches with all driver names. If * is specified, the
@@ -3398,6 +3418,7 @@
33983418
nospectre_bhb [ARM64]
33993419
nospectre_v1 [X86,PPC]
34003420
nospectre_v2 [X86,PPC,S390,ARM64]
3421+
reg_file_data_sampling=off [X86]
34013422
retbleed=off [X86]
34023423
spec_store_bypass_disable=off [X86,PPC]
34033424
spectre_v2_user=off [X86]

arch/x86/Kconfig

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

26152615
If in doubt, say N.
26162616

2617+
config MITIGATION_RFDS
2618+
bool "RFDS Mitigation"
2619+
depends on CPU_SUP_INTEL
2620+
default y
2621+
help
2622+
Enable mitigation for Register File Data Sampling (RFDS) by default.
2623+
RFDS is a hardware vulnerability which affects Intel Atom CPUs. It
2624+
allows unprivileged speculative access to stale data previously
2625+
stored in floating point, vector and integer registers.
2626+
See also <file:Documentation/admin-guide/hw-vuln/reg-file-data-sampling.rst>
2627+
26172628
endif
26182629

26192630
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
@@ -503,4 +503,5 @@
503503
/* BUG word 2 */
504504
#define X86_BUG_SRSO X86_BUG(1*32 + 0) /* AMD SRSO bug */
505505
#define X86_BUG_DIV0 X86_BUG(1*32 + 1) /* AMD DIV0 speculation bug */
506+
#define X86_BUG_RFDS X86_BUG(1*32 + 2) /* CPU is vulnerable to Register File Data Sampling */
506507
#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
@@ -165,6 +165,14 @@
165165
* CPU is not vulnerable to Gather
166166
* Data Sampling (GDS).
167167
*/
168+
#define ARCH_CAP_RFDS_NO BIT(27) /*
169+
* Not susceptible to Register
170+
* File Data Sampling.
171+
*/
172+
#define ARCH_CAP_RFDS_CLEAR BIT(28) /*
173+
* VERW clears CPU Register
174+
* File.
175+
*/
168176

169177
#define ARCH_CAP_XAPIC_DISABLE BIT(21) /*
170178
* 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
@@ -480,6 +480,57 @@ static int __init mmio_stale_data_parse_cmdline(char *str)
480480
}
481481
early_param("mmio_stale_data", mmio_stale_data_parse_cmdline);
482482

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

@@ -513,6 +564,11 @@ static void __init md_clear_update_mitigation(void)
513564
mmio_mitigation = MMIO_MITIGATION_VERW;
514565
mmio_select_mitigation();
515566
}
567+
if (rfds_mitigation == RFDS_MITIGATION_OFF &&
568+
boot_cpu_has_bug(X86_BUG_RFDS)) {
569+
rfds_mitigation = RFDS_MITIGATION_VERW;
570+
rfds_select_mitigation();
571+
}
516572
out:
517573
if (boot_cpu_has_bug(X86_BUG_MDS))
518574
pr_info("MDS: %s\n", mds_strings[mds_mitigation]);
@@ -522,18 +578,21 @@ static void __init md_clear_update_mitigation(void)
522578
pr_info("MMIO Stale Data: %s\n", mmio_strings[mmio_mitigation]);
523579
else if (boot_cpu_has_bug(X86_BUG_MMIO_UNKNOWN))
524580
pr_info("MMIO Stale Data: Unknown: No mitigations\n");
581+
if (boot_cpu_has_bug(X86_BUG_RFDS))
582+
pr_info("Register File Data Sampling: %s\n", rfds_strings[rfds_mitigation]);
525583
}
526584

527585
static void __init md_clear_select_mitigation(void)
528586
{
529587
mds_select_mitigation();
530588
taa_select_mitigation();
531589
mmio_select_mitigation();
590+
rfds_select_mitigation();
532591

533592
/*
534-
* As MDS, TAA and MMIO Stale Data mitigations are inter-related, update
535-
* and print their mitigation after MDS, TAA and MMIO Stale Data
536-
* mitigation selection is done.
593+
* As these mitigations are inter-related and rely on VERW instruction
594+
* to clear the microarchitural buffers, update and print their status
595+
* after mitigation selection is done for each of these vulnerabilities.
537596
*/
538597
md_clear_update_mitigation();
539598
}
@@ -2622,6 +2681,11 @@ static ssize_t mmio_stale_data_show_state(char *buf)
26222681
sched_smt_active() ? "vulnerable" : "disabled");
26232682
}
26242683

2684+
static ssize_t rfds_show_state(char *buf)
2685+
{
2686+
return sysfs_emit(buf, "%s\n", rfds_strings[rfds_mitigation]);
2687+
}
2688+
26252689
static char *stibp_state(void)
26262690
{
26272691
if (spectre_v2_in_eibrs_mode(spectre_v2_enabled) &&
@@ -2781,6 +2845,9 @@ static ssize_t cpu_show_common(struct device *dev, struct device_attribute *attr
27812845
case X86_BUG_GDS:
27822846
return gds_show_state(buf);
27832847

2848+
case X86_BUG_RFDS:
2849+
return rfds_show_state(buf);
2850+
27842851
default:
27852852
break;
27862853
}
@@ -2855,4 +2922,9 @@ ssize_t cpu_show_gds(struct device *dev, struct device_attribute *attr, char *bu
28552922
{
28562923
return cpu_show_common(dev, attr, buf, X86_BUG_GDS);
28572924
}
2925+
2926+
ssize_t cpu_show_reg_file_data_sampling(struct device *dev, struct device_attribute *attr, char *buf)
2927+
{
2928+
return cpu_show_common(dev, attr, buf, X86_BUG_RFDS);
2929+
}
28582930
#endif

arch/x86/kernel/cpu/common.c

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1267,6 +1267,8 @@ static const __initconst struct x86_cpu_id cpu_vuln_whitelist[] = {
12671267
#define SRSO BIT(5)
12681268
/* CPU is affected by GDS */
12691269
#define GDS BIT(6)
1270+
/* CPU is affected by Register File Data Sampling */
1271+
#define RFDS BIT(7)
12701272

12711273
static const struct x86_cpu_id cpu_vuln_blacklist[] __initconst = {
12721274
VULNBL_INTEL_STEPPINGS(IVYBRIDGE, X86_STEPPING_ANY, SRBDS),
@@ -1294,9 +1296,18 @@ static const struct x86_cpu_id cpu_vuln_blacklist[] __initconst = {
12941296
VULNBL_INTEL_STEPPINGS(TIGERLAKE, X86_STEPPING_ANY, GDS),
12951297
VULNBL_INTEL_STEPPINGS(LAKEFIELD, X86_STEPPING_ANY, MMIO | MMIO_SBDS | RETBLEED),
12961298
VULNBL_INTEL_STEPPINGS(ROCKETLAKE, X86_STEPPING_ANY, MMIO | RETBLEED | GDS),
1297-
VULNBL_INTEL_STEPPINGS(ATOM_TREMONT, X86_STEPPING_ANY, MMIO | MMIO_SBDS),
1298-
VULNBL_INTEL_STEPPINGS(ATOM_TREMONT_D, X86_STEPPING_ANY, MMIO),
1299-
VULNBL_INTEL_STEPPINGS(ATOM_TREMONT_L, X86_STEPPING_ANY, MMIO | MMIO_SBDS),
1299+
VULNBL_INTEL_STEPPINGS(ALDERLAKE, X86_STEPPING_ANY, RFDS),
1300+
VULNBL_INTEL_STEPPINGS(ALDERLAKE_L, X86_STEPPING_ANY, RFDS),
1301+
VULNBL_INTEL_STEPPINGS(RAPTORLAKE, X86_STEPPING_ANY, RFDS),
1302+
VULNBL_INTEL_STEPPINGS(RAPTORLAKE_P, X86_STEPPING_ANY, RFDS),
1303+
VULNBL_INTEL_STEPPINGS(RAPTORLAKE_S, X86_STEPPING_ANY, RFDS),
1304+
VULNBL_INTEL_STEPPINGS(ATOM_GRACEMONT, X86_STEPPING_ANY, RFDS),
1305+
VULNBL_INTEL_STEPPINGS(ATOM_TREMONT, X86_STEPPING_ANY, MMIO | MMIO_SBDS | RFDS),
1306+
VULNBL_INTEL_STEPPINGS(ATOM_TREMONT_D, X86_STEPPING_ANY, MMIO | RFDS),
1307+
VULNBL_INTEL_STEPPINGS(ATOM_TREMONT_L, X86_STEPPING_ANY, MMIO | MMIO_SBDS | RFDS),
1308+
VULNBL_INTEL_STEPPINGS(ATOM_GOLDMONT, X86_STEPPING_ANY, RFDS),
1309+
VULNBL_INTEL_STEPPINGS(ATOM_GOLDMONT_D, X86_STEPPING_ANY, RFDS),
1310+
VULNBL_INTEL_STEPPINGS(ATOM_GOLDMONT_PLUS, X86_STEPPING_ANY, RFDS),
13001311

13011312
VULNBL_AMD(0x15, RETBLEED),
13021313
VULNBL_AMD(0x16, RETBLEED),
@@ -1330,6 +1341,24 @@ static bool arch_cap_mmio_immune(u64 ia32_cap)
13301341
ia32_cap & ARCH_CAP_SBDR_SSDP_NO);
13311342
}
13321343

1344+
static bool __init vulnerable_to_rfds(u64 ia32_cap)
1345+
{
1346+
/* The "immunity" bit trumps everything else: */
1347+
if (ia32_cap & ARCH_CAP_RFDS_NO)
1348+
return false;
1349+
1350+
/*
1351+
* VMMs set ARCH_CAP_RFDS_CLEAR for processors not in the blacklist to
1352+
* indicate that mitigation is needed because guest is running on a
1353+
* vulnerable hardware or may migrate to such hardware:
1354+
*/
1355+
if (ia32_cap & ARCH_CAP_RFDS_CLEAR)
1356+
return true;
1357+
1358+
/* Only consult the blacklist when there is no enumeration: */
1359+
return cpu_matches(cpu_vuln_blacklist, RFDS);
1360+
}
1361+
13331362
static void __init cpu_set_bug_bits(struct cpuinfo_x86 *c)
13341363
{
13351364
u64 ia32_cap = x86_read_arch_cap_msr();
@@ -1441,6 +1470,9 @@ static void __init cpu_set_bug_bits(struct cpuinfo_x86 *c)
14411470
boot_cpu_has(X86_FEATURE_AVX))
14421471
setup_force_cpu_bug(X86_BUG_GDS);
14431472

1473+
if (vulnerable_to_rfds(ia32_cap))
1474+
setup_force_cpu_bug(X86_BUG_RFDS);
1475+
14441476
if (cpu_matches(cpu_vuln_whitelist, NO_MELTDOWN))
14451477
return;
14461478

drivers/base/cpu.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -588,6 +588,7 @@ CPU_SHOW_VULN_FALLBACK(mmio_stale_data);
588588
CPU_SHOW_VULN_FALLBACK(retbleed);
589589
CPU_SHOW_VULN_FALLBACK(spec_rstack_overflow);
590590
CPU_SHOW_VULN_FALLBACK(gds);
591+
CPU_SHOW_VULN_FALLBACK(reg_file_data_sampling);
591592

592593
static DEVICE_ATTR(meltdown, 0444, cpu_show_meltdown, NULL);
593594
static DEVICE_ATTR(spectre_v1, 0444, cpu_show_spectre_v1, NULL);
@@ -602,6 +603,7 @@ static DEVICE_ATTR(mmio_stale_data, 0444, cpu_show_mmio_stale_data, NULL);
602603
static DEVICE_ATTR(retbleed, 0444, cpu_show_retbleed, NULL);
603604
static DEVICE_ATTR(spec_rstack_overflow, 0444, cpu_show_spec_rstack_overflow, NULL);
604605
static DEVICE_ATTR(gather_data_sampling, 0444, cpu_show_gds, NULL);
606+
static DEVICE_ATTR(reg_file_data_sampling, 0444, cpu_show_reg_file_data_sampling, NULL);
605607

606608
static struct attribute *cpu_root_vulnerabilities_attrs[] = {
607609
&dev_attr_meltdown.attr,
@@ -617,6 +619,7 @@ static struct attribute *cpu_root_vulnerabilities_attrs[] = {
617619
&dev_attr_retbleed.attr,
618620
&dev_attr_spec_rstack_overflow.attr,
619621
&dev_attr_gather_data_sampling.attr,
622+
&dev_attr_reg_file_data_sampling.attr,
620623
NULL
621624
};
622625

include/linux/cpu.h

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

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

0 commit comments

Comments
 (0)