From c6d0b5450b2aeab2aa200428212be9f6794223a1 Mon Sep 17 00:00:00 2001 From: Vasily Gorbik Date: Tue, 29 Mar 2022 10:20:08 +0200 Subject: [PATCH 1/7] lookup: fix symtab parsing symtab_read tries to skip '.dynsym' symbol table and only read '.symtab' symbol table. Newer readelf from binutils 2.37 now adds section names (see the diff): --- vmlinux.symtab 2022-02-18 02:10:06.691220932 +0100 +++ vmlinux.symtab.new 2022-02-18 01:16:06.161210458 +0100 Symbol table '.dynsym' contains 1541 entries: Num: Value Size Type Bind Vis Ndx Name 0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND 1: 0000000000100000 0 SECTION LOCAL DEFAULT 1 .text 2: 00000000017a3ac0 4 OBJECT GLOBAL DEFAULT 19 sclp_console_pages Symbol table '.symtab' contains 159980 entries: Num: Value Size Type Bind Vis Ndx Name - 41: 0000000001a93600 0 SECTION LOCAL DEFAULT 41 - 42: 0000000001a9c678 0 SECTION LOCAL DEFAULT 42 ... + 41: 0000000001a93600 0 SECTION LOCAL DEFAULT 41 .dynsym + 42: 0000000001a9c678 0 SECTION LOCAL DEFAULT 42 .rela.dyn ... 54: 0000000000000000 0 FILE LOCAL DEFAULT ABS main.c Simple matching of ".dynsym" in the line buffer is not enough anymore, because it hits not just Symbol table '.dynsym' contains 1541 entries: line, but also 41: 0000000001a93600 0 SECTION LOCAL DEFAULT 41 .dynsym skipping the rest of the file and leading to an error: create-diff-object: ERROR: *.o: find_local_syms: 189: couldn't find matching *.c local symbols in vmlinux symbol table Limit matching only to lines containing "Symbol table" header. This works with readelf from the binutils, as well as readelf from elfutils (its output looks slightly different). Symbol table [41] '.dynsym' contains 1541 entries: Signed-off-by: Vasily Gorbik --- kpatch-build/lookup.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/kpatch-build/lookup.c b/kpatch-build/lookup.c index 06f4b3848..c9e6cc7f1 100644 --- a/kpatch-build/lookup.c +++ b/kpatch-build/lookup.c @@ -272,12 +272,14 @@ static void symtab_read(struct lookup_table *table, char *path) * tables. .dynsym is just a subset of .symtab, so skip it to * avoid duplicates. */ - if (strstr(line, ".dynsym")) { - skip = true; - continue; - } else if (strstr(line, ".symtab")) { - skip = false; - continue; + if (!strncmp(line, "Symbol table ", 13)) { + if (strstr(line, ".dynsym")) { + skip = true; + continue; + } else if (strstr(line, ".symtab")) { + skip = false; + continue; + } } if (skip) continue; From 10002f5aa671de2878252aaa48f585457d39638a Mon Sep 17 00:00:00 2001 From: Sumanth Korikkar Date: Tue, 29 Mar 2022 10:20:19 +0200 Subject: [PATCH 2/7] kpatch/s390: Add gcc prerequisite flags for kpatch 1. -mno-pic-data-is-text-relative prevents relative addressing between code and data. This is needed to avoid relocation error when klp text and data are too far apart 2. Avoid generation of LANCHOR symbols through -fno-section-anchors. kpatch-build does not handle it well. Signed-off-by: Sumanth Korikkar --- kpatch-build/kpatch-build | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/kpatch-build/kpatch-build b/kpatch-build/kpatch-build index 9f0fc6db5..7cdae87e5 100755 --- a/kpatch-build/kpatch-build +++ b/kpatch-build/kpatch-build @@ -937,6 +937,10 @@ if [[ "$ARCH" = "ppc64le" ]]; then ARCH_KCFLAGS="-mcmodel=large -fplugin=$PLUGINDIR/ppc64le-plugin.so" fi +if [[ "$ARCH" = "s390x" ]]; then + ARCH_KCFLAGS="-mno-pic-data-is-text-relative -fno-section-anchors" +fi + export KCFLAGS="-I$DATADIR/patch -ffunction-sections -fdata-sections \ $ARCH_KCFLAGS $DEBUG_KCFLAGS" From f0d00a9290e7d0c97a6b1bf134384859dd224bf7 Mon Sep 17 00:00:00 2001 From: Sumanth Korikkar Date: Tue, 29 Mar 2022 10:20:32 +0200 Subject: [PATCH 3/7] kpatch/s390: Add initial support for kpatch * Add s390 specific checks * Identify patchable functions. * Dont mark expolines as dynrelas. These expolines are always included in final kernel module. This ensures that expoline functions and the kernel itself are not too far apart and avoids out of range relocation. However, this isnt a problem for other functions, as these relocations are performed via R_390_PLT32DBL using gcc option -mno-pic-data-is-text-relative. * s390 maintains expoline tables to locate the expoline thunks. If needed, the module loader could later replace these expoline thunks with normal indirect branch. Each element in the expoline table is of 4 bytes. If there is a changed function in rela.s390_return*, then mark that specific rela symbol as included. This is already performed in the processing of special sections. Hence include it. Signed-off-by: Sumanth Korikkar --- kpatch-build/create-diff-object.c | 78 +++++++++++++++++++++++++++---- kpatch-build/kpatch-build | 19 +++++--- kpatch-build/kpatch-elf.c | 22 +++++++++ 3 files changed, 105 insertions(+), 14 deletions(-) diff --git a/kpatch-build/create-diff-object.c b/kpatch-build/create-diff-object.c index bebe3bd15..4a7665444 100644 --- a/kpatch-build/create-diff-object.c +++ b/kpatch-build/create-diff-object.c @@ -163,6 +163,8 @@ static bool is_gcc6_localentry_bundled_sym(struct kpatch_elf *kelf, sym->sym.st_value == 8); case X86_64: return false; + case S390: + return false; default: ERROR("unsupported arch"); } @@ -304,8 +306,7 @@ static bool is_dynamic_debug_symbol(struct symbol *sym) static bool is_string_literal_section(struct section *sec) { - return !strncmp(sec->name, ".rodata.", 8) && - strstr(sec->name, ".str1."); + return !strncmp(sec->name, ".rodata.", 8) && strstr(sec->name, ".str"); } /* @@ -2104,6 +2105,17 @@ static int fixup_barrier_nospec_group_size(struct kpatch_elf *kelf, int offset) return 8; } +/* + * .s390_indirect_jump, .s390_indirect_call, .s390_indirect_branches, + * .s390_return_reg, .s390_return_mem contains indirect branch locations. This + * is an array of 32 bit elements. These sections could be used during runtime + * to replace the expolines with the normal indirect jump. + */ +static int s390_expolines_group_size(struct kpatch_elf *kelf, int offset) +{ + return 4; +} + /* * The rela groups in the .fixup section vary in size. The beginning of each * .fixup rela group is referenced by the __ex_table section. To find the size @@ -2157,27 +2169,27 @@ static int fixup_group_size(struct kpatch_elf *kelf, int offset) static struct special_section special_sections[] = { { .name = "__bug_table", - .arch = X86_64 | PPC64, + .arch = X86_64 | PPC64 | S390, .group_size = bug_table_group_size, }, { .name = ".fixup", - .arch = X86_64 | PPC64, + .arch = X86_64 | PPC64 | S390, .group_size = fixup_group_size, }, { .name = "__ex_table", /* must come after .fixup */ - .arch = X86_64 | PPC64, + .arch = X86_64 | PPC64 | S390, .group_size = ex_table_group_size, }, { .name = "__jump_table", - .arch = X86_64 | PPC64, + .arch = X86_64 | PPC64 | S390, .group_size = jump_table_group_size, }, { .name = ".printk_index", - .arch = X86_64 | PPC64, + .arch = X86_64 | PPC64 | S390, .group_size = printk_index_group_size, }, { @@ -2192,7 +2204,7 @@ static struct special_section special_sections[] = { }, { .name = ".altinstructions", - .arch = X86_64, + .arch = X86_64 | S390, .group_size = altinstructions_group_size, }, { @@ -2230,6 +2242,31 @@ static struct special_section special_sections[] = { .arch = PPC64, .group_size = fixup_barrier_nospec_group_size, }, + { + .name = ".s390_return_mem", + .arch = S390, + .group_size = s390_expolines_group_size, + }, + { + .name = ".s390_return_reg", + .arch = S390, + .group_size = s390_expolines_group_size, + }, + { + .name = ".s390_indirect_call", + .arch = S390, + .group_size = s390_expolines_group_size, + }, + { + .name = ".s390_indirect_branches", + .arch = S390, + .group_size = s390_expolines_group_size, + }, + { + .name = ".s390_indirect_jump", + .arch = S390, + .group_size = s390_expolines_group_size, + }, {}, }; @@ -3024,6 +3061,11 @@ static bool kpatch_is_core_module_symbol(char *name) !strcmp(name, "kpatch_shadow_get")); } +static bool is_expoline(struct kpatch_elf *kelf, char *name) +{ + return kelf->arch == S390 && !strncmp(name, "__s390_indirect_jump_r", 22); +} + static int function_ptr_rela(const struct rela *rela) { const struct rela *rela_toc = toc_rela(rela); @@ -3082,6 +3124,13 @@ static bool need_dynrela(struct kpatch_elf *kelf, struct lookup_table *table, if (kpatch_is_core_module_symbol(rela->sym->name)) return false; + /* + * Allow references to s390 expolines to remain as normal relas. They + * will be generated in the module by the kernel module link. + */ + if (is_expoline(kelf, rela->sym->name)) + return false; + if (rela->sym->sec) { /* * Internal symbols usually don't need dynrelas, because they @@ -3548,6 +3597,10 @@ static void kpatch_create_mcount_sections(struct kpatch_elf *kelf) rela->type = R_X86_64_PC32; break; } + case S390: { + insn_offset = sym->sym.st_value; + break; + } default: ERROR("unsupported arch"); } @@ -3713,6 +3766,7 @@ static void kpatch_find_func_profiling_calls(struct kpatch_elf *kelf) { struct symbol *sym; struct rela *rela; + unsigned char *insn; list_for_each_entry(sym, &kelf->symbols, list) { if (sym->type != STT_FUNC || !sym->sec || !sym->sec->rela) continue; @@ -3737,6 +3791,14 @@ static void kpatch_find_func_profiling_calls(struct kpatch_elf *kelf) sym->has_func_profiling = 1; break; + case S390: + /* Check for compiler generated fentry nop - jgnop 0 */ + insn = sym->sec->data->d_buf; + if (insn[0] == 0xc0 && insn[1] == 0x04 && + insn[2] == 0x00 && insn[3] == 0x00 && + insn[4] == 0x00 && insn[5] == 0x00) + sym->has_func_profiling = 1; + break; default: ERROR("unsupported arch"); } diff --git a/kpatch-build/kpatch-build b/kpatch-build/kpatch-build index 7cdae87e5..02504e60b 100755 --- a/kpatch-build/kpatch-build +++ b/kpatch-build/kpatch-build @@ -343,12 +343,18 @@ find_special_section_data() { check[e]=true # exception_table_entry # Arch-specific features, without kernel CONFIG_ toggle - if [[ "$ARCH" = "x86_64" ]]; then - check[a]=true # alt_instr - kernel_version_gte 5.10.0 && check[s]=true # static_call_site - elif [[ "$ARCH" = "ppc64le" ]]; then - check[f]=true # fixup_entry - fi + case "$ARCH" in + "x86_64") + check[a]=true # alt_instr + kernel_version_gte 5.10.0 && check[s]=true # static_call_site + ;; + "ppc64le") + check[f]=true # fixup_entry + ;; + "s390x") + check[a]=true # alt_instr + ;; + esac # Kernel CONFIG_ features [[ -n "$CONFIG_PRINTK_INDEX" ]] && check[i]=true # pi_entry @@ -856,6 +862,7 @@ trace_on die "openEuler kernel doesn't have 'CONFIG_LIVEPATCH_PER_TASK_CONSISTENCY' enabled" [[ -z "$CONFIG_DEBUG_INFO" ]] && die "kernel doesn't have 'CONFIG_DEBUG_INFO' enabled" +[[ "$ARCH" = "s390x" ]] && [[ -z "$CONFIG_EXPOLINE_EXTERN" ]] && [[ -n "$CONFIG_EXPOLINE" ]] && die "kernel doesn't have 'CONFIG_EXPOLINE_EXTERN' enabled" # Build variables - Set some defaults, then adjust features # according to .config and kernel version diff --git a/kpatch-build/kpatch-elf.c b/kpatch-build/kpatch-elf.c index 6a43ef5b9..92881e915 100644 --- a/kpatch-build/kpatch-elf.c +++ b/kpatch-build/kpatch-elf.c @@ -140,6 +140,8 @@ unsigned int absolute_rela_type(struct kpatch_elf *kelf) return R_PPC64_ADDR64; case X86_64: return R_X86_64_64; + case S390: + return R_390_64; default: ERROR("unsupported arch"); } @@ -222,6 +224,23 @@ long rela_target_offset(struct kpatch_elf *kelf, struct section *relasec, } else ERROR("unhandled rela type %d", rela->type); break; + case S390: + /* + * For branch and relative load instructions, + * add_off is -2. + */ + if (rela->type == R_390_GOTENT || + rela->type == R_390_PLT32DBL || + rela->type == R_390_PC32DBL) + add_off = -2; + else if (rela->type == R_390_32 || + rela->type == R_390_64 || + rela->type == R_390_PC32 || + rela->type == R_390_PC64) + add_off = 0; + else + ERROR("unhandled rela type %d", rela->type); + break; default: ERROR("unsupported arch\n"); } @@ -479,6 +498,9 @@ struct kpatch_elf *kpatch_elf_open(const char *name) case EM_X86_64: kelf->arch = X86_64; break; + case EM_S390: + kelf->arch = S390; + break; default: ERROR("Unsupported target architecture"); } From eb4a85f778cbb738a9e14052b860f051f98631f5 Mon Sep 17 00:00:00 2001 From: Sumanth Korikkar Date: Tue, 29 Mar 2022 10:20:41 +0200 Subject: [PATCH 4/7] kpatch/s390: Add exclusion lists Add object exclusion for s390 Signed-off-by: Sumanth Korikkar --- kpatch-build/kpatch-cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/kpatch-build/kpatch-cc b/kpatch-build/kpatch-cc index 476436fd7..5474a13bb 100755 --- a/kpatch-build/kpatch-cc +++ b/kpatch-build/kpatch-cc @@ -43,6 +43,9 @@ if [[ "$TOOLCHAINCMD" =~ ^(.*-)?gcc$ || "$TOOLCHAINCMD" =~ ^(.*-)?clang$ ]] ; th drivers/firmware/efi/libstub/*|\ arch/powerpc/kernel/prom_init.o|\ arch/powerpc/kernel/vdso64/*|\ + arch/s390/boot/*|\ + arch/s390/purgatory/*|\ + arch/s390/kernel/vdso64/*|\ lib/*|\ .*.o|\ */.lib_exports.o) From b0330ab18ee4da5514b4dbc55582ec642688ff12 Mon Sep 17 00:00:00 2001 From: Sumanth Korikkar Date: Tue, 29 Mar 2022 10:20:47 +0200 Subject: [PATCH 5/7] kpatch/s390: Add additional bundled symbols. 1. static const struct inet_sock fake_sk = { /* makes ip6_route_output set RT6_LOOKUP_F_IFACE: */ .sk.sk_bound_dev_if = 1, .pinet6 = (struct ipv6_pinfo *) &fake_pinfo, }; gcc can place fake_sk in .data.rel.ro.local: ndx 38, data 0x3ffb3280a58, size 960, name .data.rel.ro.local.fake_sk.1 ndx 39, data 0x3ffb32be5e8, size 24, name .rela.data.rel.ro.local.fake_sk.1 2. static LIST_HEAD(patch_objects); gcc can place patch_objects relocation in .data.rel.local: sym 56, type 1, bind 0, ndx 34, name patch_objects -> .data.rel.local Signed-off-by: Sumanth Korikkar --- kpatch-build/create-diff-object.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/kpatch-build/create-diff-object.c b/kpatch-build/create-diff-object.c index 4a7665444..5f9cd1903 100644 --- a/kpatch-build/create-diff-object.c +++ b/kpatch-build/create-diff-object.c @@ -118,6 +118,16 @@ static bool is_bundleable(struct symbol *sym) !strcmp(sym->sec->name + 13, sym->name)) return true; + if (sym->type == STT_OBJECT && + !strncmp(sym->sec->name, ".data.rel.ro.local.", 19) && + !strcmp(sym->sec->name + 19, sym->name)) + return 1; + + if (sym->type == STT_OBJECT && + !strncmp(sym->sec->name, ".data.rel.local.", 16) && + !strcmp(sym->sec->name + 16, sym->name)) + return 1; + if (sym->type == STT_OBJECT && !strncmp(sym->sec->name, ".rodata.",8) && !strcmp(sym->sec->name + 8, sym->name)) From 0308d52bcd7ba5f28ef5208ec5fc76a719cba8eb Mon Sep 17 00:00:00 2001 From: Sumanth Korikkar Date: Tue, 29 Mar 2022 10:21:07 +0200 Subject: [PATCH 6/7] kpatch/s390: Enable kpatch build support Signed-off-by: Sumanth Korikkar --- kpatch-build/Makefile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/kpatch-build/Makefile b/kpatch-build/Makefile index da96edff0..bebf3cd96 100644 --- a/kpatch-build/Makefile +++ b/kpatch-build/Makefile @@ -21,7 +21,8 @@ GCC_PLUGINS_DIR := $(shell $(CROSS_COMPILE)gcc -print-file-name=plugin) PLUGIN_CFLAGS := $(filter-out -Wconversion, $(CFLAGS)) PLUGIN_CFLAGS += -shared -I$(GCC_PLUGINS_DIR)/include \ -Igcc-plugins -fPIC -fno-rtti -O2 -Wall -else ifneq ($(ARCH),x86_64) +endif +ifeq ($(filter $(ARCH),s390x x86_64 ppc64le),) $(error Unsupported architecture ${ARCH}, check https://github.com/dynup/kpatch/#supported-architectures) endif From 48d997f2a39c9151670b254570679b24d40abb7d Mon Sep 17 00:00:00 2001 From: Sumanth Korikkar Date: Tue, 29 Mar 2022 10:21:26 +0200 Subject: [PATCH 7/7] README: Update s390 as supported and backporting info * Add s390 as supported. * Add backporting information for the distros. Signed-off-by: Sumanth Korikkar --- README.md | 2 +- doc/s390-upstream-prerequisites.md | 33 ++++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+), 1 deletion(-) create mode 100644 doc/s390-upstream-prerequisites.md diff --git a/README.md b/README.md index 29696f842..3b0a98d34 100644 --- a/README.md +++ b/README.md @@ -41,7 +41,7 @@ Supported Architectures - [x] x86-64 - [x] ppc64le - [ ] arm64 -- [ ] s390 +- [x] s390 [upstream prerequisites](doc/s390-upstream-prerequisites.md) Installation ------------ diff --git a/doc/s390-upstream-prerequisites.md b/doc/s390-upstream-prerequisites.md new file mode 100644 index 000000000..11173ef57 --- /dev/null +++ b/doc/s390-upstream-prerequisites.md @@ -0,0 +1,33 @@ +### s390 backporting + +**Prerequisite gcc patches (all backported to releases/gcc-11 branch):** +- gcc-mirror/gcc@a1c1b7a IBM Z: Define NO_PROFILE_COUNTERS +- gcc-mirror/gcc@0990d93 IBM Z: Use @PLT symbols for local functions in 64-bit mode +- gcc-mirror/gcc@935b522 S/390: New option -mpic-data-is-text-relative +- gcc-mirror/gcc@8753b13 IBM Z: fix section type conflict with -mindirect-branch-table + +**Prerequisite kernel patches:** +**v5.19:** +- 69505e3d9a39 bug: Use normal relative pointers in 'struct bug_entry' + +**v5.18:** +- 602bf1687e6f s390/nospec: align and size extern thunks +- 1d2ad084800e s390/nospec: add an option to use thunk-extern +- eed38cd2f46f s390/nospec: generate single register thunks if possible +- 2268169c14e5 s390: remove unused expoline to BC instructions +- f0003a9e4c18 s390/entry: remove unused expoline thunk + +**v5.16:** +- torvalds/linux@f6ac18f sched: Improve try_invoke_on_locked_down_task() +- torvalds/linux@9b3c4ab sched,rcu: Rework try_invoke_on_locked_down_task() +- torvalds/linux@00619f7 sched,livepatch: Use task_call_func() +- torvalds/linux@8850cb6 sched: Simplify wake_up_*idle*() +- torvalds/linux@5de62ea sched,livepatch: Use wake_up_if_idle() +- torvalds/linux@96611c2 sched: Improve wake_up_all_idle_cpus() take #2 + +**v5.15** +- torvalds/linux@de5012b s390/ftrace: implement hotpatching +- torvalds/linux@67ccddf ftrace: Introduce ftrace_need_init_nop() + +**v5.14:** +- torvalds/linux@7561c14 s390/vdso: add .got.plt in vdso linker script