From: Pavel Machek <pavel@ucw.cz>
To: Martin Schwidefsky <schwidefsky@de.ibm.com>
Cc: linux-kernel@vger.kernel.org, linux-s390@vger.kernel.org,
Heiko Carstens <heiko.carstens@de.ibm.com>,
Christian Borntraeger <borntraeger@de.ibm.com>,
Cornelia Huck <cohuck@redhat.com>,
David Hildenbrand <david@redhat.com>,
Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
Jon Masters <jcm@redhat.com>, Marcus Meissner <meissner@suse.de>,
Jiri Kosina <jkosina@suse.cz>,
Dominik Brodowski <linux@dominikbrodowski.net>,
Alan Cox <gnomes@lxorguk.ukuu.org.uk>,
David Woodhouse <dwmw2@infradead.org>
Subject: Re: [PATCH 6/6] s390: introduce execute-trampolines for branches
Date: Wed, 7 Feb 2018 11:07:26 +0100 [thread overview]
Message-ID: <20180207100726.GB31392@amd> (raw)
In-Reply-To: <1517986811-27819-7-git-send-email-schwidefsky@de.ibm.com>
[-- Attachment #1: Type: text/plain, Size: 23264 bytes --]
On Wed 2018-02-07 08:00:11, Martin Schwidefsky wrote:
> Add CONFIG_EXPOLINE to enable the use of the new -mindirect-branch= and
> -mfunction_return= compiler options to create a kernel fortified against
> the specte v2 attack.
>
> With CONFIG_EXPOLINE=y all indirect branches will be issued with an
> execute type instruction. For z10 or newer the EXRL instruction will
> be used, for older machines the EX instruction. The typical indirect
> call
>
> basr %r14,%r1
>
> is replaced with a PC relative call to a new thunk
>
> brasl %r14,__s390x_indirect_jump_r1
>
> The thunk contains the EXRL/EX instruction to the indirect branch
>
> __s390x_indirect_jump_r1:
> exrl 0,0f
> j .
> 0: br %r1
>
> The detour via the execute type instruction has a performance impact.
> To get rid of the detour the new kernel parameter "nospectre_v2" and
> "spectre_v2=[on,off,auto]" can be used. If the parameter is specified
> the kernel and module code will be patched at runtime.
This is really unfortunate naming of kernel option.
spectre_v2=off sounds like we are turning the "bug" off, but i somehow
suspect you are turning the bug _workaround_ off.
Pavel
> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
> ---
> arch/s390/Kconfig | 28 +++++++++
> arch/s390/Makefile | 12 ++++
> arch/s390/include/asm/lowcore.h | 6 +-
> arch/s390/include/asm/nospec-branch.h | 18 ++++++
> arch/s390/kernel/Makefile | 4 ++
> arch/s390/kernel/entry.S | 113 ++++++++++++++++++++++++++--------
> arch/s390/kernel/module.c | 62 ++++++++++++++++---
> arch/s390/kernel/nospec-branch.c | 100 ++++++++++++++++++++++++++++++
> arch/s390/kernel/setup.c | 4 ++
> arch/s390/kernel/smp.c | 1 +
> arch/s390/kernel/vmlinux.lds.S | 14 +++++
> drivers/s390/char/Makefile | 2 +
> 12 files changed, 329 insertions(+), 35 deletions(-)
> create mode 100644 arch/s390/include/asm/nospec-branch.h
> create mode 100644 arch/s390/kernel/nospec-branch.c
>
> diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig
> index d514e25..d4a65bf 100644
> --- a/arch/s390/Kconfig
> +++ b/arch/s390/Kconfig
> @@ -557,6 +557,34 @@ config KERNEL_NOBP
>
> If unsure, say N.
>
> +config EXPOLINE
> + def_bool n
> + prompt "Avoid speculative indirect branches in the kernel"
> + help
> + Compile the kernel with the expoline compiler options to guard
> + against kernel-to-user data leaks by avoiding speculative indirect
> + branches.
> + Requires a compiler with -mindirect-branch=thunk support for full
> + protection. The kernel may run slower.
> +
> + If unsure, say N.
> +
> +choice
> + prompt "Expoline default"
> + depends on EXPOLINE
> + default EXPOLINE_FULL
> +
> +config EXPOLINE_OFF
> + bool "spectre_v2=off"
> +
> +config EXPOLINE_MEDIUM
> + bool "spectre_v2=auto"
> +
> +config EXPOLINE_FULL
> + bool "spectre_v2=on"
> +
> +endchoice
> +
> endmenu
>
> menu "Memory setup"
> diff --git a/arch/s390/Makefile b/arch/s390/Makefile
> index fd691c4..2f925ef 100644
> --- a/arch/s390/Makefile
> +++ b/arch/s390/Makefile
> @@ -78,6 +78,18 @@ ifeq ($(call cc-option-yn,-mwarn-dynamicstack),y)
> cflags-$(CONFIG_WARN_DYNAMIC_STACK) += -mwarn-dynamicstack
> endif
>
> +ifdef CONFIG_EXPOLINE
> + ifeq ($(call cc-option-yn,$(CC_FLAGS_MARCH) -mindirect-branch=thunk),y)
> + CC_FLAGS_EXPOLINE := -mindirect-branch=thunk
> + CC_FLAGS_EXPOLINE += -mfunction-return=thunk
> + CC_FLAGS_EXPOLINE += -mindirect-branch-table
> + export CC_FLAGS_EXPOLINE
> + cflags-y += $(CC_FLAGS_EXPOLINE)
> + else
> + $(warning "Your gcc lacks the -mindirect-branch= option")
> + endif
> +endif
> +
> ifdef CONFIG_FUNCTION_TRACER
> # make use of hotpatch feature if the compiler supports it
> cc_hotpatch := -mhotpatch=0,3
> diff --git a/arch/s390/include/asm/lowcore.h b/arch/s390/include/asm/lowcore.h
> index c63986a..5bc8888 100644
> --- a/arch/s390/include/asm/lowcore.h
> +++ b/arch/s390/include/asm/lowcore.h
> @@ -136,7 +136,11 @@ struct lowcore {
> __u64 vdso_per_cpu_data; /* 0x03b8 */
> __u64 machine_flags; /* 0x03c0 */
> __u64 gmap; /* 0x03c8 */
> - __u8 pad_0x03d0[0x0e00-0x03d0]; /* 0x03d0 */
> + __u8 pad_0x03d0[0x0400-0x03d0]; /* 0x03d0 */
> +
> + /* br %r1 trampoline */
> + __u16 br_r1_trampoline; /* 0x0400 */
> + __u8 pad_0x0402[0x0e00-0x0402]; /* 0x0402 */
>
> /*
> * 0xe00 contains the address of the IPL Parameter Information
> diff --git a/arch/s390/include/asm/nospec-branch.h b/arch/s390/include/asm/nospec-branch.h
> new file mode 100644
> index 0000000..7df48e5
> --- /dev/null
> +++ b/arch/s390/include/asm/nospec-branch.h
> @@ -0,0 +1,18 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +#ifndef _ASM_S390_EXPOLINE_H
> +#define _ASM_S390_EXPOLINE_H
> +
> +#ifndef __ASSEMBLY__
> +
> +#include <linux/types.h>
> +
> +extern int nospec_call_disable;
> +extern int nospec_return_disable;
> +
> +void nospec_init_branches(void);
> +void nospec_call_revert(s32 *start, s32 *end);
> +void nospec_return_revert(s32 *start, s32 *end);
> +
> +#endif /* __ASSEMBLY__ */
> +
> +#endif /* _ASM_S390_EXPOLINE_H */
> diff --git a/arch/s390/kernel/Makefile b/arch/s390/kernel/Makefile
> index 909bce6..7f27e3d 100644
> --- a/arch/s390/kernel/Makefile
> +++ b/arch/s390/kernel/Makefile
> @@ -29,6 +29,7 @@ UBSAN_SANITIZE_early.o := n
> #
> ifneq ($(CC_FLAGS_MARCH),-march=z900)
> CFLAGS_REMOVE_als.o += $(CC_FLAGS_MARCH)
> +CFLAGS_REMOVE_als.o += $(CC_FLAGS_EXPOLINE)
> CFLAGS_als.o += -march=z900
> AFLAGS_REMOVE_head.o += $(CC_FLAGS_MARCH)
> AFLAGS_head.o += -march=z900
> @@ -63,6 +64,9 @@ obj-y += entry.o reipl.o relocate_kernel.o kdebugfs.o alternative.o
>
> extra-y += head.o head64.o vmlinux.lds
>
> +obj-$(CONFIG_EXPOLINE) += nospec-branch.o
> +CFLAGS_REMOVE_expoline.o += $(CC_FLAGS_EXPOLINE)
> +
> obj-$(CONFIG_MODULES) += module.o
> obj-$(CONFIG_SMP) += smp.o
> obj-$(CONFIG_SCHED_TOPOLOGY) += topology.o
> diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S
> index 53145b5..13a133a 100644
> --- a/arch/s390/kernel/entry.S
> +++ b/arch/s390/kernel/entry.S
> @@ -222,6 +222,68 @@ _PIF_WORK = (_PIF_PER_TRAP | _PIF_SYSCALL_RESTART)
> .popsection
> .endm
>
> +#ifdef CONFIG_EXPOLINE
> +
> + .macro GEN_BR_THUNK name,reg,tmp
> + .section .text.\name,"axG",@progbits,\name,comdat
> + .globl \name
> + .hidden \name
> + .type \name,@function
> +\name:
> + .cfi_startproc
> +#ifdef CONFIG_HAVE_MARCH_Z10_FEATURES
> + exrl 0,0f
> +#else
> + larl \tmp,0f
> + ex 0,0(\tmp)
> +#endif
> + j .
> +0: br \reg
> + .cfi_endproc
> + .endm
> +
> + GEN_BR_THUNK __s390x_indirect_jump_r1use_r9,%r9,%r1
> + GEN_BR_THUNK __s390x_indirect_jump_r1use_r14,%r14,%r1
> + GEN_BR_THUNK __s390x_indirect_jump_r11use_r14,%r14,%r11
> +
> + .macro BASR_R14_R9
> +0: brasl %r14,__s390x_indirect_jump_r1use_r9
> + .pushsection .s390_indirect_branches,"a",@progbits
> + .long 0b-.
> + .popsection
> + .endm
> +
> + .macro BR_R1USE_R14
> +0: jg __s390x_indirect_jump_r1use_r14
> + .pushsection .s390_indirect_branches,"a",@progbits
> + .long 0b-.
> + .popsection
> + .endm
> +
> + .macro BR_R11USE_R14
> +0: jg __s390x_indirect_jump_r11use_r14
> + .pushsection .s390_indirect_branches,"a",@progbits
> + .long 0b-.
> + .popsection
> + .endm
> +
> +#else /* CONFIG_EXPOLINE */
> +
> + .macro BASR_R14_R9
> + basr %r14,%r9
> + .endm
> +
> + .macro BR_R1USE_R14
> + br %r14
> + .endm
> +
> + .macro BR_R11USE_R14
> + br %r14
> + .endm
> +
> +#endif /* CONFIG_EXPOLINE */
> +
> +
> .section .kprobes.text, "ax"
> .Ldummy:
> /*
> @@ -237,7 +299,7 @@ _PIF_WORK = (_PIF_PER_TRAP | _PIF_SYSCALL_RESTART)
> ENTRY(__bpon)
> .globl __bpon
> BPON
> - br %r14
> + BR_R1USE_R14
>
> /*
> * Scheduler resume function, called by switch_to
> @@ -261,9 +323,9 @@ ENTRY(__switch_to)
> mvc __LC_CURRENT_PID(4,%r0),0(%r3) # store pid of next
> lmg %r6,%r15,__SF_GPRS(%r15) # load gprs of next task
> TSTMSK __LC_MACHINE_FLAGS,MACHINE_FLAG_LPP
> - bzr %r14
> + jz 0f
> .insn s,0xb2800000,__LC_LPP # set program parameter
> - br %r14
> +0: BR_R1USE_R14
>
> .L__critical_start:
>
> @@ -330,7 +392,7 @@ sie_exit:
> xgr %r5,%r5
> lmg %r6,%r14,__SF_GPRS(%r15) # restore kernel registers
> lg %r2,__SF_EMPTY+16(%r15) # return exit reason code
> - br %r14
> + BR_R1USE_R14
> .Lsie_fault:
> lghi %r14,-EFAULT
> stg %r14,__SF_EMPTY+16(%r15) # set exit reason code
> @@ -389,7 +451,7 @@ ENTRY(system_call)
> lgf %r9,0(%r8,%r10) # get system call add.
> TSTMSK __TI_flags(%r12),_TIF_TRACE
> jnz .Lsysc_tracesys
> - basr %r14,%r9 # call sys_xxxx
> + BASR_R14_R9 # call sys_xxxx
> stg %r2,__PT_R2(%r11) # store return value
>
> .Lsysc_return:
> @@ -574,7 +636,7 @@ ENTRY(system_call)
> lmg %r3,%r7,__PT_R3(%r11)
> stg %r7,STACK_FRAME_OVERHEAD(%r15)
> lg %r2,__PT_ORIG_GPR2(%r11)
> - basr %r14,%r9 # call sys_xxx
> + BASR_R14_R9 # call sys_xxx
> stg %r2,__PT_R2(%r11) # store return value
> .Lsysc_tracenogo:
> TSTMSK __TI_flags(%r12),_TIF_TRACE
> @@ -598,7 +660,7 @@ ENTRY(ret_from_fork)
> lmg %r9,%r10,__PT_R9(%r11) # load gprs
> ENTRY(kernel_thread_starter)
> la %r2,0(%r10)
> - basr %r14,%r9
> + BASR_R14_R9
> j .Lsysc_tracenogo
>
> /*
> @@ -678,9 +740,9 @@ ENTRY(pgm_check_handler)
> nill %r10,0x007f
> sll %r10,2
> je .Lpgm_return
> - lgf %r1,0(%r10,%r1) # load address of handler routine
> + lgf %r9,0(%r10,%r1) # load address of handler routine
> lgr %r2,%r11 # pass pointer to pt_regs
> - basr %r14,%r1 # branch to interrupt-handler
> + BASR_R14_R9 # branch to interrupt-handler
> .Lpgm_return:
> LOCKDEP_SYS_EXIT
> tm __PT_PSW+1(%r11),0x01 # returning to user ?
> @@ -998,7 +1060,7 @@ ENTRY(psw_idle)
> stpt __TIMER_IDLE_ENTER(%r2)
> .Lpsw_idle_lpsw:
> lpswe __SF_EMPTY(%r15)
> - br %r14
> + BR_R1USE_R14
> .Lpsw_idle_end:
>
> /*
> @@ -1012,7 +1074,7 @@ ENTRY(save_fpu_regs)
> lg %r2,__LC_CURRENT
> aghi %r2,__TASK_thread
> TSTMSK __LC_CPU_FLAGS,_CIF_FPU
> - bor %r14
> + jo .Lsave_fpu_regs_exit
> stfpc __THREAD_FPU_fpc(%r2)
> lg %r3,__THREAD_FPU_regs(%r2)
> TSTMSK __LC_MACHINE_FLAGS,MACHINE_FLAG_VX
> @@ -1039,7 +1101,8 @@ ENTRY(save_fpu_regs)
> std 15,120(%r3)
> .Lsave_fpu_regs_done:
> oi __LC_CPU_FLAGS+7,_CIF_FPU
> - br %r14
> +.Lsave_fpu_regs_exit:
> + BR_R1USE_R14
> .Lsave_fpu_regs_end:
> EXPORT_SYMBOL(save_fpu_regs)
>
> @@ -1057,7 +1120,7 @@ load_fpu_regs:
> lg %r4,__LC_CURRENT
> aghi %r4,__TASK_thread
> TSTMSK __LC_CPU_FLAGS,_CIF_FPU
> - bnor %r14
> + jno .Lload_fpu_regs_exit
> lfpc __THREAD_FPU_fpc(%r4)
> TSTMSK __LC_MACHINE_FLAGS,MACHINE_FLAG_VX
> lg %r4,__THREAD_FPU_regs(%r4) # %r4 <- reg save area
> @@ -1084,7 +1147,8 @@ load_fpu_regs:
> ld 15,120(%r4)
> .Lload_fpu_regs_done:
> ni __LC_CPU_FLAGS+7,255-_CIF_FPU
> - br %r14
> +.Lload_fpu_regs_exit:
> + BR_R1USE_R14
> .Lload_fpu_regs_end:
>
> .L__critical_end:
> @@ -1301,7 +1365,7 @@ cleanup_critical:
> jl 0f
> clg %r9,BASED(.Lcleanup_table+104) # .Lload_fpu_regs_end
> jl .Lcleanup_load_fpu_regs
> -0: br %r14
> +0: BR_R11USE_R14
>
> .align 8
> .Lcleanup_table:
> @@ -1337,7 +1401,7 @@ cleanup_critical:
> ni __SIE_PROG0C+3(%r9),0xfe # no longer in SIE
> lctlg %c1,%c1,__LC_USER_ASCE # load primary asce
> larl %r9,sie_exit # skip forward to sie_exit
> - br %r14
> + BR_R11USE_R14
> #endif
>
> .Lcleanup_system_call:
> @@ -1390,7 +1454,7 @@ cleanup_critical:
> stg %r15,56(%r11) # r15 stack pointer
> # set new psw address and exit
> larl %r9,.Lsysc_do_svc
> - br %r14
> + BR_R11USE_R14
> .Lcleanup_system_call_insn:
> .quad system_call
> .quad .Lsysc_stmg
> @@ -1402,7 +1466,7 @@ cleanup_critical:
>
> .Lcleanup_sysc_tif:
> larl %r9,.Lsysc_tif
> - br %r14
> + BR_R11USE_R14
>
> .Lcleanup_sysc_restore:
> # check if stpt has been executed
> @@ -1419,14 +1483,14 @@ cleanup_critical:
> mvc 0(64,%r11),__PT_R8(%r9)
> lmg %r0,%r7,__PT_R0(%r9)
> 1: lmg %r8,%r9,__LC_RETURN_PSW
> - br %r14
> + BR_R11USE_R14
> .Lcleanup_sysc_restore_insn:
> .quad .Lsysc_exit_timer
> .quad .Lsysc_done - 4
>
> .Lcleanup_io_tif:
> larl %r9,.Lio_tif
> - br %r14
> + BR_R11USE_R14
>
> .Lcleanup_io_restore:
> # check if stpt has been executed
> @@ -1440,7 +1504,7 @@ cleanup_critical:
> mvc 0(64,%r11),__PT_R8(%r9)
> lmg %r0,%r7,__PT_R0(%r9)
> 1: lmg %r8,%r9,__LC_RETURN_PSW
> - br %r14
> + BR_R11USE_R14
> .Lcleanup_io_restore_insn:
> .quad .Lio_exit_timer
> .quad .Lio_done - 4
> @@ -1493,17 +1557,17 @@ cleanup_critical:
> # prepare return psw
> nihh %r8,0xfcfd # clear irq & wait state bits
> lg %r9,48(%r11) # return from psw_idle
> - br %r14
> + BR_R11USE_R14
> .Lcleanup_idle_insn:
> .quad .Lpsw_idle_lpsw
>
> .Lcleanup_save_fpu_regs:
> larl %r9,save_fpu_regs
> - br %r14
> + BR_R11USE_R14
>
> .Lcleanup_load_fpu_regs:
> larl %r9,load_fpu_regs
> - br %r14
> + BR_R11USE_R14
>
> /*
> * Integer constants
> @@ -1523,7 +1587,6 @@ cleanup_critical:
> .Lsie_crit_mcck_length:
> .quad .Lsie_skip - .Lsie_entry
> #endif
> -
> .section .rodata, "a"
> #define SYSCALL(esame,emu) .long esame
> .globl sys_call_table
> diff --git a/arch/s390/kernel/module.c b/arch/s390/kernel/module.c
> index b7abfad..1fc6d1f 100644
> --- a/arch/s390/kernel/module.c
> +++ b/arch/s390/kernel/module.c
> @@ -19,6 +19,8 @@
> #include <linux/moduleloader.h>
> #include <linux/bug.h>
> #include <asm/alternative.h>
> +#include <asm/nospec-branch.h>
> +#include <asm/facility.h>
>
> #if 0
> #define DEBUGP printk
> @@ -156,7 +158,11 @@ int module_frob_arch_sections(Elf_Ehdr *hdr, Elf_Shdr *sechdrs,
> me->arch.got_offset = me->core_layout.size;
> me->core_layout.size += me->arch.got_size;
> me->arch.plt_offset = me->core_layout.size;
> - me->core_layout.size += me->arch.plt_size;
> + if (me->arch.plt_size) {
> + if (IS_ENABLED(CONFIG_EXPOLINE) && !nospec_call_disable)
> + me->arch.plt_size += PLT_ENTRY_SIZE;
> + me->core_layout.size += me->arch.plt_size;
> + }
> return 0;
> }
>
> @@ -310,9 +316,21 @@ static int apply_rela(Elf_Rela *rela, Elf_Addr base, Elf_Sym *symtab,
> unsigned int *ip;
> ip = me->core_layout.base + me->arch.plt_offset +
> info->plt_offset;
> - ip[0] = 0x0d10e310; /* basr 1,0; lg 1,10(1); br 1 */
> - ip[1] = 0x100a0004;
> - ip[2] = 0x07f10000;
> + ip[0] = 0x0d10e310; /* basr 1,0 */
> + ip[1] = 0x100a0004; /* lg 1,10(1) */
> + if (IS_ENABLED(CONFIG_EXPOLINE) &&
> + !nospec_call_disable) {
> + unsigned int *ij;
> + ij = me->core_layout.base +
> + me->arch.plt_offset +
> + me->arch.plt_size - PLT_ENTRY_SIZE;
> + ip[2] = 0xa7f40000 + /* j __jump_r1 */
> + (unsigned int)(u16)
> + (((unsigned long) ij - 8 -
> + (unsigned long) ip) / 2);
> + } else {
> + ip[2] = 0x07f10000; /* br %r1 */
> + }
> ip[3] = (unsigned int) (val >> 32);
> ip[4] = (unsigned int) val;
> info->plt_initialized = 1;
> @@ -418,16 +436,42 @@ int module_finalize(const Elf_Ehdr *hdr,
> struct module *me)
> {
> const Elf_Shdr *s;
> - char *secstrings;
> + char *secstrings, *secname;
> + void *aseg;
> +
> + if (IS_ENABLED(CONFIG_EXPOLINE) &&
> + !nospec_call_disable && me->arch.plt_size) {
> + unsigned int *ij;
> +
> + ij = me->core_layout.base + me->arch.plt_offset +
> + me->arch.plt_size - PLT_ENTRY_SIZE;
> + if (test_facility(35)) {
> + ij[0] = 0xc6000000; /* exrl %r0,.+10 */
> + ij[1] = 0x0005a7f4; /* j . */
> + ij[2] = 0x000007f1; /* br %r1 */
> + } else {
> + ij[0] = 0x44000000 | (unsigned int)
> + offsetof(struct lowcore, br_r1_trampoline);
> + ij[1] = 0xa7f40000; /* j . */
> + }
> + }
>
> secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
> for (s = sechdrs; s < sechdrs + hdr->e_shnum; s++) {
> - if (!strcmp(".altinstructions", secstrings + s->sh_name)) {
> - /* patch .altinstructions */
> - void *aseg = (void *)s->sh_addr;
> + aseg = (void *) s->sh_addr;
> + secname = secstrings + s->sh_name;
>
> + if (!strcmp(".altinstructions", secname))
> + /* patch .altinstructions */
> apply_alternatives(aseg, aseg + s->sh_size);
> - }
> +
> + if (IS_ENABLED(CONFIG_EXPOLINE) &&
> + (!strcmp(".nospec_call_table", secname)))
> + nospec_call_revert(aseg, aseg + s->sh_size);
> +
> + if (IS_ENABLED(CONFIG_EXPOLINE) &&
> + (!strcmp(".nospec_return_table", secname)))
> + nospec_return_revert(aseg, aseg + s->sh_size);
> }
>
> jump_label_apply_nops(me);
> diff --git a/arch/s390/kernel/nospec-branch.c b/arch/s390/kernel/nospec-branch.c
> new file mode 100644
> index 0000000..69d7fcf
> --- /dev/null
> +++ b/arch/s390/kernel/nospec-branch.c
> @@ -0,0 +1,100 @@
> +// SPDX-License-Identifier: GPL-2.0
> +#include <linux/module.h>
> +#include <asm/nospec-branch.h>
> +
> +int nospec_call_disable = IS_ENABLED(EXPOLINE_OFF);
> +int nospec_return_disable = !IS_ENABLED(EXPOLINE_FULL);
> +
> +static int __init nospectre_v2_setup_early(char *str)
> +{
> + nospec_call_disable = 1;
> + nospec_return_disable = 1;
> + return 0;
> +}
> +early_param("nospectre_v2", nospectre_v2_setup_early);
> +
> +static int __init spectre_v2_setup_early(char *str)
> +{
> + if (str && !strncmp(str, "on", 2)) {
> + nospec_call_disable = 0;
> + nospec_return_disable = 0;
> + }
> + if (str && !strncmp(str, "off", 3)) {
> + nospec_call_disable = 1;
> + nospec_return_disable = 1;
> + }
> + if (str && !strncmp(str, "auto", 4)) {
> + nospec_call_disable = 0;
> + nospec_return_disable = 1;
> + }
> + return 0;
> +}
> +early_param("spectre_v2", spectre_v2_setup_early);
> +
> +static void __init_or_module __nospec_revert(s32 *start, s32 *end)
> +{
> + enum { BRCL_EXPOLINE, BRASL_EXPOLINE } type;
> + u8 *instr, *thunk, *br;
> + u8 insnbuf[6];
> + s32 *epo;
> +
> + /* Second part of the instruction replace is always a nop */
> + memcpy(insnbuf + 2, (char[]) { 0x47, 0x00, 0x00, 0x00 }, 4);
> + for (epo = start; epo < end; epo++) {
> + instr = (u8 *) epo + *epo;
> + if (instr[0] == 0xc0 && (instr[1] & 0x0f) == 0x04)
> + type = BRCL_EXPOLINE; /* brcl instruction */
> + else if (instr[0] == 0xc0 && (instr[1] & 0x0f) == 0x05)
> + type = BRASL_EXPOLINE; /* brasl instruction */
> + else
> + continue;
> + thunk = instr + (*(int *)(instr + 2)) * 2;
> + if (thunk[0] == 0xc6 && thunk[1] == 0x00)
> + /* exrl %r0,<target-br> */
> + br = thunk + (*(int *)(thunk + 2)) * 2;
> + else if (thunk[0] == 0xc0 && (thunk[1] & 0x0f) == 0x00 &&
> + thunk[6] == 0x44 && thunk[7] == 0x00 &&
> + (thunk[8] & 0x0f) == 0x00 && thunk[9] == 0x00 &&
> + (thunk[1] & 0xf0) == (thunk[8] & 0xf0))
> + /* larl %rx,<target br> + ex %r0,0(%rx) */
> + br = thunk + (*(int *)(thunk + 2)) * 2;
> + else
> + continue;
> + if (br[0] != 0x07 || (br[1] & 0xf0) != 0xf0)
> + continue;
> + switch (type) {
> + case BRCL_EXPOLINE:
> + /* brcl to thunk, replace with br + nop */
> + insnbuf[0] = br[0];
> + insnbuf[1] = (instr[1] & 0xf0) | (br[1] & 0x0f);
> + break;
> + case BRASL_EXPOLINE:
> + /* brasl to thunk, replace with basr + nop */
> + insnbuf[0] = 0x0d;
> + insnbuf[1] = (instr[1] & 0xf0) | (br[1] & 0x0f);
> + break;
> + }
> +
> + s390_kernel_write(instr, insnbuf, 6);
> + }
> +}
> +
> +void __init_or_module nospec_call_revert(s32 *start, s32 *end)
> +{
> + if (nospec_call_disable)
> + __nospec_revert(start, end);
> +}
> +
> +void __init_or_module nospec_return_revert(s32 *start, s32 *end)
> +{
> + if (nospec_return_disable)
> + __nospec_revert(start, end);
> +}
> +
> +extern s32 __nospec_call_start[], __nospec_call_end[];
> +extern s32 __nospec_return_start[], __nospec_return_end[];
> +void __init nospec_init_branches(void)
> +{
> + nospec_call_revert(__nospec_call_start, __nospec_call_end);
> + nospec_return_revert(__nospec_return_start, __nospec_return_end);
> +}
> diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c
> index bcd2a4a..a6a91f0 100644
> --- a/arch/s390/kernel/setup.c
> +++ b/arch/s390/kernel/setup.c
> @@ -68,6 +68,7 @@
> #include <asm/sysinfo.h>
> #include <asm/numa.h>
> #include <asm/alternative.h>
> +#include <asm/nospec-branch.h>
> #include "entry.h"
>
> /*
> @@ -379,6 +380,7 @@ static void __init setup_lowcore(void)
> lc->spinlock_index = 0;
> arch_spin_lock_setup(0);
> #endif
> + lc->br_r1_trampoline = 0x07f1; /* br %r1 */
>
> set_prefix((u32)(unsigned long) lc);
> lowcore_ptr[0] = lc;
> @@ -954,6 +956,8 @@ void __init setup_arch(char **cmdline_p)
> set_preferred_console();
>
> apply_alternative_instructions();
> + if (IS_ENABLED(CONFIG_EXPOLINE))
> + nospec_init_branches();
>
> /* Setup zfcpdump support */
> setup_zfcpdump();
> diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c
> index 2fd7d60..a4a9fe1 100644
> --- a/arch/s390/kernel/smp.c
> +++ b/arch/s390/kernel/smp.c
> @@ -214,6 +214,7 @@ static int pcpu_alloc_lowcore(struct pcpu *pcpu, int cpu)
> lc->cpu_nr = cpu;
> lc->spinlock_lockval = arch_spin_lockval(cpu);
> lc->spinlock_index = 0;
> + lc->br_r1_trampoline = 0x07f1; /* br %r1 */
> if (nmi_alloc_per_cpu(lc))
> goto out;
> if (vdso_alloc_per_cpu(lc))
> diff --git a/arch/s390/kernel/vmlinux.lds.S b/arch/s390/kernel/vmlinux.lds.S
> index 608cf29..08d12cf 100644
> --- a/arch/s390/kernel/vmlinux.lds.S
> +++ b/arch/s390/kernel/vmlinux.lds.S
> @@ -123,6 +123,20 @@ SECTIONS
> *(.altinstr_replacement)
> }
>
> + /*
> + * Table with the patch locations to undo expolines
> + */
> + .nospec_call_table : {
> + __nospec_call_start = . ;
> + *(.s390_indirect*)
> + __nospec_call_end = . ;
> + }
> + .nospec_return_table : {
> + __nospec_return_start = . ;
> + *(.s390_return*)
> + __nospec_return_end = . ;
> + }
> +
> /* early.c uses stsi, which requires page aligned data. */
> . = ALIGN(PAGE_SIZE);
> INIT_DATA_SECTION(0x100)
> diff --git a/drivers/s390/char/Makefile b/drivers/s390/char/Makefile
> index 614b44e..a2b33a2 100644
> --- a/drivers/s390/char/Makefile
> +++ b/drivers/s390/char/Makefile
> @@ -19,6 +19,8 @@ endif
>
> CFLAGS_sclp_early_core.o += -D__NO_FORTIFY
>
> +CFLAGS_REMOVE_sclp_early_core.o += $(CC_FLAGS_EXPOLINE)
> +
> obj-y += ctrlchar.o keyboard.o defkeymap.o sclp.o sclp_rw.o sclp_quiesce.o \
> sclp_cmd.o sclp_config.o sclp_cpi_sys.o sclp_ocf.o sclp_ctl.o \
> sclp_early.o sclp_early_core.o
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 181 bytes --]
next prev parent reply other threads:[~2018-02-07 10:07 UTC|newest]
Thread overview: 19+ messages / expand[flat|nested] mbox.gz Atom feed top
2018-02-07 7:00 [PATCH 0/6] s390: improve speculative execution handling v3 Martin Schwidefsky
2018-02-07 7:00 ` [PATCH 1/6] s390: scrub registers on kernel entry and KVM exit Martin Schwidefsky
2018-02-07 7:00 ` [PATCH 2/6] s390: add optimized array_index_mask_nospec Martin Schwidefsky
2018-02-07 7:00 ` [PATCH 3/6] s390/alternative: use a copy of the facility bit mask Martin Schwidefsky
2018-02-07 7:00 ` [PATCH 4/6] s390: add options to change branch prediction behaviour for the kernel Martin Schwidefsky
2018-02-07 10:02 ` Pavel Machek
2018-02-07 11:49 ` Martin Schwidefsky
2018-02-07 7:00 ` [PATCH 5/6] s390: run user space and KVM guests with modified branch prediction Martin Schwidefsky
2018-02-07 7:00 ` [PATCH 6/6] s390: introduce execute-trampolines for branches Martin Schwidefsky
2018-02-07 10:07 ` Pavel Machek [this message]
2018-02-07 11:51 ` Martin Schwidefsky
2018-02-07 12:07 ` David Woodhouse
2018-02-07 12:17 ` Martin Schwidefsky
2018-02-07 12:20 ` David Woodhouse
2018-02-07 17:55 ` Linus Torvalds
2018-02-07 23:44 ` Masahiro Yamada
2018-02-08 0:05 ` Linus Torvalds
2018-02-08 0:57 ` Kees Cook
2018-02-08 17:11 ` Masahiro Yamada
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20180207100726.GB31392@amd \
--to=pavel@ucw.cz \
--cc=borntraeger@de.ibm.com \
--cc=cohuck@redhat.com \
--cc=david@redhat.com \
--cc=dwmw2@infradead.org \
--cc=gnomes@lxorguk.ukuu.org.uk \
--cc=gregkh@linuxfoundation.org \
--cc=heiko.carstens@de.ibm.com \
--cc=jcm@redhat.com \
--cc=jkosina@suse.cz \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-s390@vger.kernel.org \
--cc=linux@dominikbrodowski.net \
--cc=meissner@suse.de \
--cc=schwidefsky@de.ibm.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.