s390/nospec: add an option to use thunk-extern
authorVasily Gorbik <gor@linux.ibm.com>
Sun, 6 Mar 2022 19:56:07 +0000 (20:56 +0100)
committerVasily Gorbik <gor@linux.ibm.com>
Thu, 10 Mar 2022 14:58:17 +0000 (15:58 +0100)
Currently with -mindirect-branch=thunk and -mfunction-return=thunk compiler
options expoline thunks are put into individual COMDAT group sections. s390
is the only architecture which has group sections and it has implications
for kpatch and objtool tools support.

Using -mindirect-branch=thunk-extern and -mfunction-return=thunk-extern
is an alternative, which comes with a need to generate all required
expoline thunks manually. Unfortunately modules area is too far away from
the kernel image, and expolines from the kernel image cannon be used.
But since all new distributions (except Debian) build kernels for machine
generations newer than z10, where "exrl" instruction is available, that
leaves only 16 expolines thunks possible.

Provide an option to build the kernel with
-mindirect-branch=thunk-extern and -mfunction-return=thunk-extern for
z10 or newer. This also requires to postlink expoline thunks into all
modules explicitly. Currently modules already contain most expolines
anyhow.

Unfortunately -mindirect-branch=thunk-extern and
-mfunction-return=thunk-extern options support is broken in gcc <= 11.2.
Additional compile test is required to verify proper gcc support.

Acked-by: Ilya Leoshkevich <iii@linux.ibm.com>
Co-developed-by: Sumanth Korikkar <sumanthk@linux.ibm.com>
Signed-off-by: Sumanth Korikkar <sumanthk@linux.ibm.com>
Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
arch/s390/Kconfig
arch/s390/Makefile
arch/s390/include/asm/nospec-insn.h
arch/s390/lib/Makefile
arch/s390/lib/expoline.S [new file with mode: 0644]
arch/s390/tools/gcc-thunk-extern.sh [new file with mode: 0755]
scripts/mod/modpost.c

index a492376d6e3f08163623c6212cba4d902a10fac8..115b8cddefeee417a29160e52022b3aa0b6c7287 100644 (file)
@@ -585,6 +585,7 @@ config KERNEL_NOBP
 
 config EXPOLINE
        def_bool n
+       depends on $(cc-option,-mindirect-branch=thunk)
        prompt "Avoid speculative indirect branches in the kernel"
        help
          Compile the kernel with the expoline compiler options to guard
@@ -595,6 +596,20 @@ config EXPOLINE
 
          If unsure, say N.
 
+config EXPOLINE_EXTERN
+       def_bool n
+       depends on EXPOLINE
+       depends on HAVE_MARCH_Z10_FEATURES
+       depends on CC_IS_GCC && GCC_VERSION >= 110200
+       depends on $(success,$(srctree)/arch/s390/tools/gcc-thunk-extern.sh $(CC))
+       prompt "Generate expolines as extern functions."
+       help
+         This option is required for some tooling like kpatch. The kernel is
+         compiled with -mindirect-branch=thunk-extern and requires a newer
+         compiler.
+
+         If unsure, say N.
+
 choice
        prompt "Expoline default"
        depends on EXPOLINE
index 2edf25b44c4b381f69c56a94ddb071bf671d14c8..bd75128b7d798719b76044560ecd47cf7c187996 100644 (file)
@@ -81,14 +81,18 @@ ifneq ($(call cc-option,-mstack-size=8192 -mstack-guard=128),)
 endif
 
 ifdef CONFIG_EXPOLINE
-  ifneq ($(call cc-option,$(CC_FLAGS_MARCH) -mindirect-branch=thunk),)
+  ifdef CONFIG_EXPOLINE_EXTERN
+    KBUILD_LDFLAGS_MODULE += arch/s390/lib/expoline.o
+    CC_FLAGS_EXPOLINE := -mindirect-branch=thunk-extern
+    CC_FLAGS_EXPOLINE += -mfunction-return=thunk-extern
+  else
     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) -DCC_USING_EXPOLINE
-    aflags-y += -DCC_USING_EXPOLINE
   endif
+  CC_FLAGS_EXPOLINE += -mindirect-branch-table
+  export CC_FLAGS_EXPOLINE
+  cflags-y += $(CC_FLAGS_EXPOLINE) -DCC_USING_EXPOLINE
+  aflags-y += -DCC_USING_EXPOLINE
 endif
 
 ifdef CONFIG_FUNCTION_TRACER
index 4397eae15e3423eaa2834ad03ba625abb9c3d9b4..bbb5c4d84db937b1a1b6603da70ca83cf100a127 100644 (file)
@@ -18,7 +18,11 @@ _LC_BR_R1 = __LC_BR_R1
  * the various thunks are merged into a single copy.
  */
        .macro __THUNK_PROLOG_NAME name
+#ifdef CONFIG_EXPOLINE_EXTERN
+       .pushsection .text,"ax",@progbits
+#else
        .pushsection .text.\name,"axG",@progbits,\name,comdat
+#endif
        .globl \name
        .hidden \name
        .type \name,@function
@@ -115,7 +119,13 @@ _LC_BR_R1 = __LC_BR_R1
 555:   br      \reg
        .endm
 
+#ifdef CONFIG_EXPOLINE_EXTERN
+       .macro GEN_BR_THUNK reg,ruse=%r1
+       .endm
+       .macro GEN_BR_THUNK_EXTERN reg,ruse=%r1
+#else
        .macro GEN_BR_THUNK reg,ruse=%r1
+#endif
        __DECODE_RR __THUNK_PROLOG_BR,\reg,\ruse
        __THUNK_EX_BR \reg,\ruse
        __THUNK_EPILOG
index 69feb8ed3312d406d0aaa72b6d08138c274a615b..5d415b3db6d14c626988667d1894d68805213cd1 100644 (file)
@@ -7,6 +7,7 @@ lib-y += delay.o string.o uaccess.o find.o spinlock.o
 obj-y += mem.o xor.o
 lib-$(CONFIG_KPROBES) += probes.o
 lib-$(CONFIG_UPROBES) += probes.o
+obj-$(CONFIG_EXPOLINE_EXTERN) += expoline.o
 obj-$(CONFIG_S390_KPROBES_SANITY_TEST) += test_kprobes_s390.o
 test_kprobes_s390-objs += test_kprobes_asm.o test_kprobes.o
 
diff --git a/arch/s390/lib/expoline.S b/arch/s390/lib/expoline.S
new file mode 100644 (file)
index 0000000..92ed840
--- /dev/null
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#include <asm/nospec-insn.h>
+#include <linux/linkage.h>
+
+.macro GEN_ALL_BR_THUNK_EXTERN
+       .irp r1,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
+       GEN_BR_THUNK_EXTERN %r\r1
+       .endr
+.endm
+
+GEN_ALL_BR_THUNK_EXTERN
diff --git a/arch/s390/tools/gcc-thunk-extern.sh b/arch/s390/tools/gcc-thunk-extern.sh
new file mode 100755 (executable)
index 0000000..20bcbf6
--- /dev/null
@@ -0,0 +1,24 @@
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0
+# Borrowed from gcc: gcc/testsuite/gcc.target/s390/nobp-section-type-conflict.c
+# Checks that we don't get error: section type conflict with ‘put_page’.
+
+cat << "END" | $@ -x c - -fno-PIE -march=z10 -mindirect-branch=thunk-extern -mfunction-return=thunk-extern -mindirect-branch-table -O2 -c -o /dev/null
+int a;
+int b (void);
+void c (int);
+
+static void
+put_page (void)
+{
+  if (b ())
+    c (a);
+}
+
+__attribute__ ((__section__ (".init.text"), __cold__)) void
+d (void)
+{
+  put_page ();
+  put_page ();
+}
+END
index 6bfa332179140bee888179e24c9346d05736c16e..dbc0aaf69e434749c9ca59c3ce0f5dafdee5fac8 100644 (file)
@@ -658,6 +658,11 @@ static int ignore_undef_symbol(struct elf_info *info, const char *symname)
                    strstarts(symname, "_savevr_") ||
                    strcmp(symname, ".TOC.") == 0)
                        return 1;
+
+       if (info->hdr->e_machine == EM_S390)
+               /* Expoline thunks are linked on all kernel modules during final link of .ko */
+               if (strstarts(symname, "__s390_indirect_jump_r"))
+                       return 1;
        /* Do not ignore this symbol */
        return 0;
 }