Skip to content

Commit 6e179d6

Browse files
author
Martin Schwidefsky
committed
s390: add automatic detection of the spectre defense
Automatically decide between nobp vs. expolines if the spectre_v2=auto kernel parameter is specified or CONFIG_EXPOLINE_AUTO=y is set. The decision made at boot time due to CONFIG_EXPOLINE_AUTO=y being set can be overruled with the nobp, nospec and spectre_v2 kernel parameters. Signed-off-by: Martin Schwidefsky <[email protected]>
1 parent b2e2f43 commit 6e179d6

File tree

6 files changed

+52
-38
lines changed

6 files changed

+52
-38
lines changed

arch/s390/Kconfig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -576,7 +576,7 @@ choice
576576
config EXPOLINE_OFF
577577
bool "spectre_v2=off"
578578

579-
config EXPOLINE_MEDIUM
579+
config EXPOLINE_AUTO
580580
bool "spectre_v2=auto"
581581

582582
config EXPOLINE_FULL

arch/s390/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ ifdef CONFIG_EXPOLINE
8181
CC_FLAGS_EXPOLINE += -mfunction-return=thunk
8282
CC_FLAGS_EXPOLINE += -mindirect-branch-table
8383
export CC_FLAGS_EXPOLINE
84-
cflags-y += $(CC_FLAGS_EXPOLINE)
84+
cflags-y += $(CC_FLAGS_EXPOLINE) -DCC_USING_EXPOLINE
8585
endif
8686
endif
8787

arch/s390/include/asm/nospec-branch.h

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,10 @@
66

77
#include <linux/types.h>
88

9-
extern int nospec_call_disable;
10-
extern int nospec_return_disable;
9+
extern int nospec_disable;
1110

1211
void nospec_init_branches(void);
13-
void nospec_call_revert(s32 *start, s32 *end);
14-
void nospec_return_revert(s32 *start, s32 *end);
12+
void nospec_revert(s32 *start, s32 *end);
1513

1614
#endif /* __ASSEMBLY__ */
1715

arch/s390/kernel/alternative.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
#include <linux/module.h>
33
#include <asm/alternative.h>
44
#include <asm/facility.h>
5+
#include <asm/nospec-branch.h>
56

67
#define MAX_PATCH_LEN (255 - 1)
78

arch/s390/kernel/module.c

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@ int module_frob_arch_sections(Elf_Ehdr *hdr, Elf_Shdr *sechdrs,
159159
me->core_layout.size += me->arch.got_size;
160160
me->arch.plt_offset = me->core_layout.size;
161161
if (me->arch.plt_size) {
162-
if (IS_ENABLED(CONFIG_EXPOLINE) && !nospec_call_disable)
162+
if (IS_ENABLED(CONFIG_EXPOLINE) && !nospec_disable)
163163
me->arch.plt_size += PLT_ENTRY_SIZE;
164164
me->core_layout.size += me->arch.plt_size;
165165
}
@@ -318,8 +318,7 @@ static int apply_rela(Elf_Rela *rela, Elf_Addr base, Elf_Sym *symtab,
318318
info->plt_offset;
319319
ip[0] = 0x0d10e310; /* basr 1,0 */
320320
ip[1] = 0x100a0004; /* lg 1,10(1) */
321-
if (IS_ENABLED(CONFIG_EXPOLINE) &&
322-
!nospec_call_disable) {
321+
if (IS_ENABLED(CONFIG_EXPOLINE) && !nospec_disable) {
323322
unsigned int *ij;
324323
ij = me->core_layout.base +
325324
me->arch.plt_offset +
@@ -440,7 +439,7 @@ int module_finalize(const Elf_Ehdr *hdr,
440439
void *aseg;
441440

442441
if (IS_ENABLED(CONFIG_EXPOLINE) &&
443-
!nospec_call_disable && me->arch.plt_size) {
442+
!nospec_disable && me->arch.plt_size) {
444443
unsigned int *ij;
445444

446445
ij = me->core_layout.base + me->arch.plt_offset +
@@ -467,11 +466,11 @@ int module_finalize(const Elf_Ehdr *hdr,
467466

468467
if (IS_ENABLED(CONFIG_EXPOLINE) &&
469468
(!strcmp(".nospec_call_table", secname)))
470-
nospec_call_revert(aseg, aseg + s->sh_size);
469+
nospec_revert(aseg, aseg + s->sh_size);
471470

472471
if (IS_ENABLED(CONFIG_EXPOLINE) &&
473472
(!strcmp(".nospec_return_table", secname)))
474-
nospec_return_revert(aseg, aseg + s->sh_size);
473+
nospec_revert(aseg, aseg + s->sh_size);
475474
}
476475

477476
jump_label_apply_nops(me);

arch/s390/kernel/nospec-branch.c

Lines changed: 42 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,17 @@ static int __init nobp_setup_early(char *str)
1010
rc = kstrtobool(str, &enabled);
1111
if (rc)
1212
return rc;
13-
if (enabled && test_facility(82))
13+
if (enabled && test_facility(82)) {
14+
/*
15+
* The user explicitely requested nobp=1, enable it and
16+
* disable the expoline support.
17+
*/
1418
__set_facility(82, S390_lowcore.alt_stfle_fac_list);
15-
else
19+
if (IS_ENABLED(CONFIG_EXPOLINE))
20+
nospec_disable = 1;
21+
} else {
1622
__clear_facility(82, S390_lowcore.alt_stfle_fac_list);
23+
}
1724
return 0;
1825
}
1926
early_param("nobp", nobp_setup_early);
@@ -27,31 +34,46 @@ early_param("nospec", nospec_setup_early);
2734

2835
#ifdef CONFIG_EXPOLINE
2936

30-
int nospec_call_disable = IS_ENABLED(CONFIG_EXPOLINE_OFF);
31-
int nospec_return_disable = !IS_ENABLED(CONFIG_EXPOLINE_FULL);
37+
int nospec_disable = IS_ENABLED(CONFIG_EXPOLINE_OFF);
3238

3339
static int __init nospectre_v2_setup_early(char *str)
3440
{
35-
nospec_call_disable = 1;
36-
nospec_return_disable = 1;
41+
nospec_disable = 1;
3742
return 0;
3843
}
3944
early_param("nospectre_v2", nospectre_v2_setup_early);
4045

46+
static int __init spectre_v2_auto_early(void)
47+
{
48+
if (IS_ENABLED(CC_USING_EXPOLINE)) {
49+
/*
50+
* The kernel has been compiled with expolines.
51+
* Keep expolines enabled and disable nobp.
52+
*/
53+
nospec_disable = 0;
54+
__clear_facility(82, S390_lowcore.alt_stfle_fac_list);
55+
}
56+
/*
57+
* If the kernel has not been compiled with expolines the
58+
* nobp setting decides what is done, this depends on the
59+
* CONFIG_KERNEL_NP option and the nobp/nospec parameters.
60+
*/
61+
return 0;
62+
}
63+
#ifdef CONFIG_EXPOLINE_AUTO
64+
early_initcall(spectre_v2_auto_early);
65+
#endif
66+
4167
static int __init spectre_v2_setup_early(char *str)
4268
{
4369
if (str && !strncmp(str, "on", 2)) {
44-
nospec_call_disable = 0;
45-
nospec_return_disable = 0;
46-
}
47-
if (str && !strncmp(str, "off", 3)) {
48-
nospec_call_disable = 1;
49-
nospec_return_disable = 1;
50-
}
51-
if (str && !strncmp(str, "auto", 4)) {
52-
nospec_call_disable = 0;
53-
nospec_return_disable = 1;
70+
nospec_disable = 0;
71+
__clear_facility(82, S390_lowcore.alt_stfle_fac_list);
5472
}
73+
if (str && !strncmp(str, "off", 3))
74+
nospec_disable = 1;
75+
if (str && !strncmp(str, "auto", 4))
76+
spectre_v2_auto_early();
5577
return 0;
5678
}
5779
early_param("spectre_v2", spectre_v2_setup_early);
@@ -104,24 +126,18 @@ static void __init_or_module __nospec_revert(s32 *start, s32 *end)
104126
}
105127
}
106128

107-
void __init_or_module nospec_call_revert(s32 *start, s32 *end)
108-
{
109-
if (nospec_call_disable)
110-
__nospec_revert(start, end);
111-
}
112-
113-
void __init_or_module nospec_return_revert(s32 *start, s32 *end)
129+
void __init_or_module nospec_revert(s32 *start, s32 *end)
114130
{
115-
if (nospec_return_disable)
131+
if (nospec_disable)
116132
__nospec_revert(start, end);
117133
}
118134

119135
extern s32 __nospec_call_start[], __nospec_call_end[];
120136
extern s32 __nospec_return_start[], __nospec_return_end[];
121137
void __init nospec_init_branches(void)
122138
{
123-
nospec_call_revert(__nospec_call_start, __nospec_call_end);
124-
nospec_return_revert(__nospec_return_start, __nospec_return_end);
139+
nospec_revert(__nospec_call_start, __nospec_call_end);
140+
nospec_revert(__nospec_return_start, __nospec_return_end);
125141
}
126142

127143
#endif /* CONFIG_EXPOLINE */

0 commit comments

Comments
 (0)