lkml.org 
[lkml]   [2018]   [Apr]   [27]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 4.14 56/80] s390: add automatic detection of the spectre defense
    Date
    4.14-stable review patch.  If anyone has any objections, please let me know.

    ------------------

    From: Martin Schwidefsky <schwidefsky@de.ibm.com>


    [ Upstream commit 6e179d64126b909f0b288fa63cdbf07c531e9b1d ]

    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 <schwidefsky@de.ibm.com>
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
    ---
    arch/s390/Kconfig | 2 -
    arch/s390/Makefile | 2 -
    arch/s390/include/asm/nospec-branch.h | 6 +--
    arch/s390/kernel/alternative.c | 1
    arch/s390/kernel/module.c | 11 ++---
    arch/s390/kernel/nospec-branch.c | 68 +++++++++++++++++++++-------------
    6 files changed, 52 insertions(+), 38 deletions(-)

    --- a/arch/s390/Kconfig
    +++ b/arch/s390/Kconfig
    @@ -575,7 +575,7 @@ choice
    config EXPOLINE_OFF
    bool "spectre_v2=off"

    -config EXPOLINE_MEDIUM
    +config EXPOLINE_AUTO
    bool "spectre_v2=auto"

    config EXPOLINE_FULL
    --- a/arch/s390/Makefile
    +++ b/arch/s390/Makefile
    @@ -87,7 +87,7 @@ ifdef CONFIG_EXPOLINE
    CC_FLAGS_EXPOLINE += -mfunction-return=thunk
    CC_FLAGS_EXPOLINE += -mindirect-branch-table
    export CC_FLAGS_EXPOLINE
    - cflags-y += $(CC_FLAGS_EXPOLINE)
    + cflags-y += $(CC_FLAGS_EXPOLINE) -DCC_USING_EXPOLINE
    endif
    endif

    --- a/arch/s390/include/asm/nospec-branch.h
    +++ b/arch/s390/include/asm/nospec-branch.h
    @@ -6,12 +6,10 @@

    #include <linux/types.h>

    -extern int nospec_call_disable;
    -extern int nospec_return_disable;
    +extern int nospec_disable;

    void nospec_init_branches(void);
    -void nospec_call_revert(s32 *start, s32 *end);
    -void nospec_return_revert(s32 *start, s32 *end);
    +void nospec_revert(s32 *start, s32 *end);

    #endif /* __ASSEMBLY__ */

    --- a/arch/s390/kernel/alternative.c
    +++ b/arch/s390/kernel/alternative.c
    @@ -1,6 +1,7 @@
    #include <linux/module.h>
    #include <asm/alternative.h>
    #include <asm/facility.h>
    +#include <asm/nospec-branch.h>

    #define MAX_PATCH_LEN (255 - 1)

    --- a/arch/s390/kernel/module.c
    +++ b/arch/s390/kernel/module.c
    @@ -172,7 +172,7 @@ int module_frob_arch_sections(Elf_Ehdr *
    me->core_layout.size += me->arch.got_size;
    me->arch.plt_offset = me->core_layout.size;
    if (me->arch.plt_size) {
    - if (IS_ENABLED(CONFIG_EXPOLINE) && !nospec_call_disable)
    + if (IS_ENABLED(CONFIG_EXPOLINE) && !nospec_disable)
    me->arch.plt_size += PLT_ENTRY_SIZE;
    me->core_layout.size += me->arch.plt_size;
    }
    @@ -331,8 +331,7 @@ static int apply_rela(Elf_Rela *rela, El
    info->plt_offset;
    ip[0] = 0x0d10e310; /* basr 1,0 */
    ip[1] = 0x100a0004; /* lg 1,10(1) */
    - if (IS_ENABLED(CONFIG_EXPOLINE) &&
    - !nospec_call_disable) {
    + if (IS_ENABLED(CONFIG_EXPOLINE) && !nospec_disable) {
    unsigned int *ij;
    ij = me->core_layout.base +
    me->arch.plt_offset +
    @@ -453,7 +452,7 @@ int module_finalize(const Elf_Ehdr *hdr,
    void *aseg;

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

    ij = me->core_layout.base + me->arch.plt_offset +
    @@ -480,11 +479,11 @@ int module_finalize(const Elf_Ehdr *hdr,

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

    if (IS_ENABLED(CONFIG_EXPOLINE) &&
    (!strcmp(".nospec_return_table", secname)))
    - nospec_return_revert(aseg, aseg + s->sh_size);
    + nospec_revert(aseg, aseg + s->sh_size);
    }

    jump_label_apply_nops(me);
    --- a/arch/s390/kernel/nospec-branch.c
    +++ b/arch/s390/kernel/nospec-branch.c
    @@ -11,10 +11,17 @@ static int __init nobp_setup_early(char
    rc = kstrtobool(str, &enabled);
    if (rc)
    return rc;
    - if (enabled && test_facility(82))
    + if (enabled && test_facility(82)) {
    + /*
    + * The user explicitely requested nobp=1, enable it and
    + * disable the expoline support.
    + */
    __set_facility(82, S390_lowcore.alt_stfle_fac_list);
    - else
    + if (IS_ENABLED(CONFIG_EXPOLINE))
    + nospec_disable = 1;
    + } else {
    __clear_facility(82, S390_lowcore.alt_stfle_fac_list);
    + }
    return 0;
    }
    early_param("nobp", nobp_setup_early);
    @@ -28,31 +35,46 @@ early_param("nospec", nospec_setup_early

    #ifdef CONFIG_EXPOLINE

    -int nospec_call_disable = IS_ENABLED(CONFIG_EXPOLINE_OFF);
    -int nospec_return_disable = !IS_ENABLED(CONFIG_EXPOLINE_FULL);
    +int nospec_disable = IS_ENABLED(CONFIG_EXPOLINE_OFF);

    static int __init nospectre_v2_setup_early(char *str)
    {
    - nospec_call_disable = 1;
    - nospec_return_disable = 1;
    + nospec_disable = 1;
    return 0;
    }
    early_param("nospectre_v2", nospectre_v2_setup_early);

    +static int __init spectre_v2_auto_early(void)
    +{
    + if (IS_ENABLED(CC_USING_EXPOLINE)) {
    + /*
    + * The kernel has been compiled with expolines.
    + * Keep expolines enabled and disable nobp.
    + */
    + nospec_disable = 0;
    + __clear_facility(82, S390_lowcore.alt_stfle_fac_list);
    + }
    + /*
    + * If the kernel has not been compiled with expolines the
    + * nobp setting decides what is done, this depends on the
    + * CONFIG_KERNEL_NP option and the nobp/nospec parameters.
    + */
    + return 0;
    +}
    +#ifdef CONFIG_EXPOLINE_AUTO
    +early_initcall(spectre_v2_auto_early);
    +#endif
    +
    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;
    + nospec_disable = 0;
    + __clear_facility(82, S390_lowcore.alt_stfle_fac_list);
    }
    + if (str && !strncmp(str, "off", 3))
    + nospec_disable = 1;
    + if (str && !strncmp(str, "auto", 4))
    + spectre_v2_auto_early();
    return 0;
    }
    early_param("spectre_v2", spectre_v2_setup_early);
    @@ -105,15 +127,9 @@ static void __init_or_module __nospec_re
    }
    }

    -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)
    +void __init_or_module nospec_revert(s32 *start, s32 *end)
    {
    - if (nospec_return_disable)
    + if (nospec_disable)
    __nospec_revert(start, end);
    }

    @@ -121,8 +137,8 @@ extern s32 __nospec_call_start[], __nosp
    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);
    + nospec_revert(__nospec_call_start, __nospec_call_end);
    + nospec_revert(__nospec_return_start, __nospec_return_end);
    }

    #endif /* CONFIG_EXPOLINE */

    \
     
     \ /
      Last update: 2018-04-27 16:46    [W:4.134 / U:0.260 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site