[xenial][PATCH 1/3] UBUNTU: SAUCE: s390: improve cpu alternative handling for gmb and nobp
Marcelo Henrique Cerri
marcelo.cerri at canonical.com
Thu Jan 18 16:13:12 UTC 2018
From: Martin Schwidefsky <schwidefsky at de.ibm.com>
CVE-2017-5753
CVE-2017-5715
Signed-off-by: Martin Schwidefsky <schwidefsky at de.ibm.com>
Signed-off-by: Marcelo Henrique Cerri <marcelo.cerri at canonical.com>
---
arch/s390/Kconfig | 17 +++++++++++++++++
arch/s390/include/asm/facility.h | 18 ++++++++++++++++++
arch/s390/include/asm/lowcore.h | 3 ++-
arch/s390/kernel/alternative.c | 32 +++++++++++++++++++++++++-------
arch/s390/kernel/early.c | 5 +++++
arch/s390/kernel/entry.S | 4 ++--
arch/s390/kernel/setup.c | 4 +++-
arch/s390/kernel/smp.c | 4 +++-
arch/s390/kernel/vmlinux.lds.S | 3 ---
9 files changed, 75 insertions(+), 15 deletions(-)
diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig
index 3a55f493c7da..1a24a3e96199 100644
--- a/arch/s390/Kconfig
+++ b/arch/s390/Kconfig
@@ -485,6 +485,23 @@ source kernel/Kconfig.preempt
source kernel/Kconfig.hz
+config KERNEL_NOBP
+ def_bool n
+ prompt "Enable modified branch prediction for the kernel by default"
+ help
+ If this option is selected the kernel will switch to a modified
+ branch prediction mode if the firmware interface is available.
+ The modified branch prediction mode improves the behaviour in
+ regard to speculative execution.
+
+ With the option enabled the kernel parameter "nobp=0" or "nospec"
+ can be used to run the kernel in the normal branch prediction mode.
+
+ With the option disabled the modified branch prediction mode is
+ enabled with the "nobp=1" kernel parameter.
+
+ If unsure, say N.
+
endmenu
menu "Memory setup"
diff --git a/arch/s390/include/asm/facility.h b/arch/s390/include/asm/facility.h
index b4f99d22ba04..f3e1313c263f 100644
--- a/arch/s390/include/asm/facility.h
+++ b/arch/s390/include/asm/facility.h
@@ -13,6 +13,24 @@
#define MAX_FACILITY_BIT (256*8) /* stfle_fac_list has 256 bytes */
+static inline void __set_facility(unsigned long nr, void *facilities)
+{
+ unsigned char *ptr = (unsigned char *) facilities;
+
+ if (nr >= MAX_FACILITY_BIT)
+ return;
+ ptr[nr >> 3] |= 0x80 >> (nr & 7);
+}
+
+static inline void __clear_facility(unsigned long nr, void *facilities)
+{
+ unsigned char *ptr = (unsigned char *) facilities;
+
+ if (nr >= MAX_FACILITY_BIT)
+ return;
+ ptr[nr >> 3] &= ~(0x80 >> (nr & 7));
+}
+
static inline int __test_facility(unsigned long nr, void *facilities)
{
unsigned char *ptr;
diff --git a/arch/s390/include/asm/lowcore.h b/arch/s390/include/asm/lowcore.h
index afe1cfebf1a4..2f8809671151 100644
--- a/arch/s390/include/asm/lowcore.h
+++ b/arch/s390/include/asm/lowcore.h
@@ -170,7 +170,8 @@ struct _lowcore {
__u8 pad_0x0e20[0x0f00-0x0e20]; /* 0x0e20 */
/* Extended facility list */
- __u64 stfle_fac_list[32]; /* 0x0f00 */
+ __u64 stfle_fac_list[16]; /* 0x0f00 */
+ __u64 alt_stfle_fac_list[16]; /* 0x0f80 */
__u8 pad_0x1000[0x11b0-0x1000]; /* 0x1000 */
/* Pointer to vector register save area */
diff --git a/arch/s390/kernel/alternative.c b/arch/s390/kernel/alternative.c
index 2281f763a9ff..4e443fe369c9 100644
--- a/arch/s390/kernel/alternative.c
+++ b/arch/s390/kernel/alternative.c
@@ -14,18 +14,35 @@ static int __init disable_alternative_instructions(char *str)
early_param("noaltinstr", disable_alternative_instructions);
-extern struct alt_instr __alt_nobp[], __alt_nobp_end[];
-static int __init nobp_setup(char *str)
+static int __init nobp_setup_early(char *str)
{
bool enabled;
int rc;
rc = strtobool(str, &enabled);
- if (!rc && enabled)
- apply_alternatives(__alt_nobp, __alt_nobp_end);
- return rc;
+ if (rc)
+ return rc;
+ if (enabled && test_facility(82))
+ __set_facility(82, S390_lowcore.alt_stfle_fac_list);
+ else
+ __clear_facility(82, S390_lowcore.alt_stfle_fac_list);
+ return 0;
+}
+early_param("nobp", nobp_setup_early);
+
+static int __init nospec_setup_early(char *str)
+{
+ __clear_facility(82, S390_lowcore.alt_stfle_fac_list);
+ return 0;
+}
+early_param("nospec", nospec_setup_early);
+
+static int __init nogmb_setup_early(char *str)
+{
+ __clear_facility(81, S390_lowcore.alt_stfle_fac_list);
+ return 0;
}
-__setup("nobp=", nobp_setup);
+early_param("nogmb", nogmb_setup_early);
struct brcl_insn {
u16 opc;
@@ -87,7 +104,8 @@ static void __init_or_module __apply_alternatives(struct alt_instr *start,
instr = (u8 *)&a->instr_offset + a->instr_offset;
replacement = (u8 *)&a->repl_offset + a->repl_offset;
- if (!test_facility(a->facility))
+ if (!__test_facility(a->facility,
+ S390_lowcore.alt_stfle_fac_list))
continue;
if (unlikely(a->instrlen % 2 || a->replacementlen % 2)) {
diff --git a/arch/s390/kernel/early.c b/arch/s390/kernel/early.c
index f82bcab0b9c3..6a4ba353b8ad 100644
--- a/arch/s390/kernel/early.c
+++ b/arch/s390/kernel/early.c
@@ -279,6 +279,11 @@ static noinline __init void setup_facility_list(void)
{
stfle(S390_lowcore.stfle_fac_list,
ARRAY_SIZE(S390_lowcore.stfle_fac_list));
+ memcpy(S390_lowcore.alt_stfle_fac_list,
+ S390_lowcore.stfle_fac_list,
+ sizeof(S390_lowcore.alt_stfle_fac_list));
+ if (!IS_ENABLED(CONFIG_KERNEL_NOBP))
+ __clear_facility(82, S390_lowcore.alt_stfle_fac_list);
}
static __init void detect_diag9c(void)
diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S
index ad97f60b699d..d990ad021124 100644
--- a/arch/s390/kernel/entry.S
+++ b/arch/s390/kernel/entry.S
@@ -167,7 +167,7 @@ _PIF_WORK = (_PIF_PER_TRAP)
660: .long 0xb2e8c000
.popsection
661: .long 0x47000000
- .pushsection .altnobp, "a"
+ .pushsection .altinstructions, "a"
.long 661b - .
.long 660b - .
.word 82
@@ -181,7 +181,7 @@ _PIF_WORK = (_PIF_PER_TRAP)
662: .long 0xb2e8d000
.popsection
663: .long 0x47000000
- .pushsection .altnobp, "a"
+ .pushsection .altinstructions, "a"
.long 663b - .
.long 662b - .
.word 82
diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c
index 136caf3128f0..e5627d4d910c 100644
--- a/arch/s390/kernel/setup.c
+++ b/arch/s390/kernel/setup.c
@@ -334,7 +334,9 @@ static void __init setup_lowcore(void)
lc->machine_flags = S390_lowcore.machine_flags;
lc->stfl_fac_list = S390_lowcore.stfl_fac_list;
memcpy(lc->stfle_fac_list, S390_lowcore.stfle_fac_list,
- MAX_FACILITY_BIT/8);
+ sizeof(lc->stfle_fac_list));
+ memcpy(lc->alt_stfle_fac_list, S390_lowcore.alt_stfle_fac_list,
+ sizeof(lc->alt_stfle_fac_list));
if (MACHINE_HAS_VX)
lc->vector_save_area_addr =
(unsigned long) &lc->vector_save_area;
diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c
index 5c06014d3bb4..6de44b6bbb0d 100644
--- a/arch/s390/kernel/smp.c
+++ b/arch/s390/kernel/smp.c
@@ -250,7 +250,9 @@ static void pcpu_prepare_secondary(struct pcpu *pcpu, int cpu)
__ctl_store(lc->cregs_save_area, 0, 15);
save_access_regs((unsigned int *) lc->access_regs_save_area);
memcpy(lc->stfle_fac_list, S390_lowcore.stfle_fac_list,
- MAX_FACILITY_BIT/8);
+ sizeof(lc->stfle_fac_list));
+ memcpy(lc->alt_stfle_fac_list, S390_lowcore.alt_stfle_fac_list,
+ sizeof(lc->alt_stfle_fac_list));
}
static void pcpu_attach_task(struct pcpu *pcpu, struct task_struct *tsk)
diff --git a/arch/s390/kernel/vmlinux.lds.S b/arch/s390/kernel/vmlinux.lds.S
index 5b96276f7b10..bcaa816ade85 100644
--- a/arch/s390/kernel/vmlinux.lds.S
+++ b/arch/s390/kernel/vmlinux.lds.S
@@ -83,9 +83,6 @@ SECTIONS
__alt_instructions = .;
*(.altinstructions)
__alt_instructions_end = .;
- __alt_nobp = .;
- *(.altnobp)
- __alt_nobp_end = .;
}
/*
--
2.7.4
More information about the kernel-team
mailing list