From 428b311440201d8804e9e8c022c6a662a85eb30b Mon Sep 17 00:00:00 2001 From: Zhipeng Xie Date: Mon, 30 Dec 2019 15:59:18 +0800 Subject: [PATCH] sync code to openeuler sync latest code to openeuler Signed-off-by: Zhipeng Xie --- ..._addressable_-to-maybe_discarded_sym.patch | 35 + ...od-patch-fix-patch-linking-with-4.20.patch | 36 + 0003-kmod-patch-more-linking-fixes.patch | 42 + ...ff-object-allow-changing-subsections.patch | 75 ++ ...-hook-don-t-active-patch-when-insmod.patch | 34 + ...port-third-party-module-make-hotpatc.patch | 208 +++++ ...port-makefile-not-in-third-party-mod.patch | 92 ++ ...ct-new-static-var-should-be-included.patch | 56 ++ ...e-THIS-modname-as-the-name-of-ddebug.patch | 32 + ...ct-fix-correlate-static-local-variab.patch | 50 ++ ...ct-don-t-create-dynamic-reloc-for-sy.patch | 31 + ...hook-support-force-enable-disable-fu.patch | 45 + ...d-support-build-patch-for-old-kernel.patch | 349 ++++++++ ...d-support-cross-compile-hotpatch-for.patch | 480 ++++++++++ ...-use-.klp.rela-in-euleros-7.5-kernel.patch | 48 + ...ct-create-dynamic-relocs-for-changed.patch | 68 ++ ...d-fix-duplicate-symbol-relocation-fo.patch | 365 ++++++++ ...ct-add-dynamic-reloction-for-functio.patch | 31 + ...ct-exclude-line-only-change-for-arm6.patch | 106 +++ ...lude-secsym-in-kpatch_mark_ignored_s.patch | 31 + 9017-support-compile-kpatch-on-aarch64.patch | 124 +++ 9018-support-c-plus-kernel-module.patch | 828 ++++++++++++++++++ 9019-fix-rodata.str-problem.patch | 28 + ...ild-adapt-for-ksymtab-in-4.19-kernel.patch | 28 + ...force-enable-disable-for-kernel-4.19.patch | 91 ++ ...h-build-adapt-for-native-compile_env.patch | 118 +++ ...special_section_data_arm64-for-arm64.patch | 96 ++ ...tic-local-symbol-for-longname-symbol.patch | 31 + 9028-add-object-in-kpatch.patch | 33 + ...mpilation-with-CONFIG_HAVE_ARCH_PREL.patch | 34 + README.md | 39 - kpatch-0.6.1.tar.gz | Bin 0 -> 147195 bytes kpatch.spec | 249 ++++++ livepatch | 65 ++ make_hotpatch | 726 +++++++++++++++ os_hotpatch | 337 +++++++ 36 files changed, 5002 insertions(+), 39 deletions(-) create mode 100644 0001-Add-__addressable_-to-maybe_discarded_sym.patch create mode 100644 0002-kmod-patch-fix-patch-linking-with-4.20.patch create mode 100644 0003-kmod-patch-more-linking-fixes.patch create mode 100644 0004-create-diff-object-allow-changing-subsections.patch create mode 100644 9001-livepatch-patch-hook-don-t-active-patch-when-insmod.patch create mode 100644 9002-kpatch-build-support-third-party-module-make-hotpatc.patch create mode 100644 9003-kpatch-build-support-makefile-not-in-third-party-mod.patch create mode 100644 9004-create-diff-object-new-static-var-should-be-included.patch create mode 100644 9005-livepatch-fix-use-THIS-modname-as-the-name-of-ddebug.patch create mode 100644 9006-create-diff-object-fix-correlate-static-local-variab.patch create mode 100644 9007-create-diff-object-don-t-create-dynamic-reloc-for-sy.patch create mode 100644 9008-livepatch-patch-hook-support-force-enable-disable-fu.patch create mode 100644 9009-kmod-kpatch-build-support-build-patch-for-old-kernel.patch create mode 100644 9010-kmod-kpatch-build-support-cross-compile-hotpatch-for.patch create mode 100644 9011-kpatch-build-use-.klp.rela-in-euleros-7.5-kernel.patch create mode 100644 9012-create-diff-object-create-dynamic-relocs-for-changed.patch create mode 100644 9013-kmod-kpatch-build-fix-duplicate-symbol-relocation-fo.patch create mode 100644 9014-create-diff-object-add-dynamic-reloction-for-functio.patch create mode 100644 9015-create-diff-object-exclude-line-only-change-for-arm6.patch create mode 100644 9016-kpatch-build-include-secsym-in-kpatch_mark_ignored_s.patch create mode 100644 9017-support-compile-kpatch-on-aarch64.patch create mode 100644 9018-support-c-plus-kernel-module.patch create mode 100644 9019-fix-rodata.str-problem.patch create mode 100644 9023-kpatch-build-adapt-for-ksymtab-in-4.19-kernel.patch create mode 100644 9024-support-force-enable-disable-for-kernel-4.19.patch create mode 100644 9025-kpatch-build-adapt-for-native-compile_env.patch create mode 100644 9026-add-find_special_section_data_arm64-for-arm64.patch create mode 100644 9027-fix-ref-static-local-symbol-for-longname-symbol.patch create mode 100644 9028-add-object-in-kpatch.patch create mode 100644 9030-kmod-core-fix-compilation-with-CONFIG_HAVE_ARCH_PREL.patch delete mode 100644 README.md create mode 100644 kpatch-0.6.1.tar.gz create mode 100644 kpatch.spec create mode 100644 livepatch create mode 100644 make_hotpatch create mode 100644 os_hotpatch diff --git a/0001-Add-__addressable_-to-maybe_discarded_sym.patch b/0001-Add-__addressable_-to-maybe_discarded_sym.patch new file mode 100644 index 0000000..8e9d463 --- /dev/null +++ b/0001-Add-__addressable_-to-maybe_discarded_sym.patch @@ -0,0 +1,35 @@ +From 722d27f6bdd4fa012e08db784bf9bb93bb75be2c Mon Sep 17 00:00:00 2001 +From: Artem Savkov +Date: Tue, 16 Oct 2018 16:05:01 +0200 +Subject: [PATCH] Add "__addressable_" to maybe_discarded_sym(). + +Starting with 1b1eeca7e4c1 "init: allow initcall tables to be emitted using +relative references" [1] __init functions are generating an "__addressable_" +symbol in a ".discarded.addressable" section so it does not show up in final +vmlinux triggering find_local_syms failures. Add "_addressable_" to the list +in maybe_discarded_sym(). + +[1] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=1b1eeca7e4c19fa76d409d4c7b338dba21f2df45 + +Signed-off-by: Artem Savkov +--- + kpatch-build/lookup.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/kpatch-build/lookup.c b/kpatch-build/lookup.c +index b88dc59..7c8e635 100644 +--- a/kpatch-build/lookup.c ++++ b/kpatch-build/lookup.c +@@ -80,7 +80,8 @@ static int maybe_discarded_sym(const char *name) + */ + if (!strncmp(name, "__exitcall_", 11) || + !strncmp(name, "__brk_reservation_fn_", 21) || +- !strncmp(name, "__func_stack_frame_non_standard_", 32)) ++ !strncmp(name, "__func_stack_frame_non_standard_", 32) || ++ !strncmp(name, "__addressable_", 14)) + return 1; + + return 0; +-- +1.7.12.4 + diff --git a/0002-kmod-patch-fix-patch-linking-with-4.20.patch b/0002-kmod-patch-fix-patch-linking-with-4.20.patch new file mode 100644 index 0000000..4fa997e --- /dev/null +++ b/0002-kmod-patch-fix-patch-linking-with-4.20.patch @@ -0,0 +1,36 @@ +From 17a97b48bcf0d486007b746c48321bab6dedb2d8 Mon Sep 17 00:00:00 2001 +From: Artem Savkov +Date: Wed, 14 Nov 2018 15:09:34 +0100 +Subject: [PATCH] kmod/patch: fix patch linking with 4.20 + +4.20 includes commit 69ea912fda74 "kbuild: remove unneeded link_multi_deps" +which changes kbuild so that only '.o' files are given to ld as targets +for linking, leaving out our linker script. Even before this commit we +were still doing this wrong and were succeeding just because ld is smart +enough to detect the script, it even throws a warning: + +ld: warning: kpatch.lds contains output sections; did you forget -T? + +The right thing to do is to add the script to ldflags either through +kbuilds 'ldflags-y' or by adding it to LDFLAGS/KPATCH_LDFLAGS directly. + +Signed-off-by: Artem Savkov +--- + kmod/patch/Makefile | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/kmod/patch/Makefile b/kmod/patch/Makefile +index 96d1fca..7ba0820 100644 +--- a/kmod/patch/Makefile ++++ b/kmod/patch/Makefile +@@ -11,6 +11,7 @@ KBUILD_CFLAGS_MODULE += -mcmodel=large + endif + + obj-m += $(KPATCH_NAME).o ++ldflags-y += -T $(src)/kpatch.lds + + $(KPATCH_NAME)-objs += patch-hook.o kpatch.lds output.o + +-- +1.7.12.4 + diff --git a/0003-kmod-patch-more-linking-fixes.patch b/0003-kmod-patch-more-linking-fixes.patch new file mode 100644 index 0000000..ab4b8bc --- /dev/null +++ b/0003-kmod-patch-more-linking-fixes.patch @@ -0,0 +1,42 @@ +From b2f40b03ce1778c7e97586e4111d22d3b28b3330 Mon Sep 17 00:00:00 2001 +From: Artem Savkov +Date: Fri, 7 Dec 2018 16:46:08 +0100 +Subject: [PATCH] kmod/patch: more linking fixes + +While adding proper linker script option my previous patch left the +linker script in the list of source files (on pre-4.20 kernels) for +ld somehow breaking kpatch callback sections. For this to work +properly kpatch.lds needs to be added to 'extra-y' instead of objs. And +for kbuild to process this option properly we need to call make without +the .ko target, i.e. let kbuild decide what to build. + +Fixes: 17a97b4 ("kmod/patch: fix patch linking with 4.20") +Signed-off-by: Artem Savkov +--- + kmod/patch/Makefile | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/kmod/patch/Makefile b/kmod/patch/Makefile +index 7ba0820..e017b17 100644 +--- a/kmod/patch/Makefile ++++ b/kmod/patch/Makefile +@@ -12,13 +12,14 @@ endif + + obj-m += $(KPATCH_NAME).o + ldflags-y += -T $(src)/kpatch.lds ++extra-y := kpatch.lds + +-$(KPATCH_NAME)-objs += patch-hook.o kpatch.lds output.o ++$(KPATCH_NAME)-objs += patch-hook.o output.o + + all: $(KPATCH_NAME).ko + + $(KPATCH_NAME).ko: +- $(KPATCH_MAKE) $(KPATCH_NAME).ko ++ $(KPATCH_MAKE) + + patch-hook.o: patch-hook.c kpatch-patch-hook.c livepatch-patch-hook.c + $(KPATCH_MAKE) patch-hook.o +-- +1.7.12.4 + diff --git a/0004-create-diff-object-allow-changing-subsections.patch b/0004-create-diff-object-allow-changing-subsections.patch new file mode 100644 index 0000000..e573d43 --- /dev/null +++ b/0004-create-diff-object-allow-changing-subsections.patch @@ -0,0 +1,75 @@ +From 942cc3ace7edb7c15f40f931dd6f47a934b9fc77 Mon Sep 17 00:00:00 2001 +From: Artem Savkov +Date: Tue, 12 Jun 2018 17:33:17 +0200 +Subject: [PATCH] create-diff-object: allow changing subsections + +gcc8 can place functions to .text.unlikely and .text.hot subsections +during optimizations. Allow symbols to change subsections instead of +failing. + +Signed-off-by: Artem Savkov + +backport from: +https://github.com/jpoimboe/kpatch/commit/35cc6ff0162fc8008c4c639fdfcabd61b38a982f +--- + kpatch-build/create-diff-object.c | 28 ++++++++++++++++++++++++++-- + 1 file changed, 26 insertions(+), 2 deletions(-) + +diff --git a/kpatch-build/create-diff-object.c b/kpatch-build/create-diff-object.c +index 2ddd00d..61ce74f 100644 +--- a/kpatch-build/create-diff-object.c ++++ b/kpatch-build/create-diff-object.c +@@ -68,6 +68,12 @@ + + char *childobj; + ++enum subsection { ++ SUBSECTION_NORMAL, ++ SUBSECTION_HOT, ++ SUBSECTION_UNLIKELY ++}; ++ + enum loglevel loglevel = NORMAL; + + #ifndef EM_X86_64 +@@ -708,6 +714,22 @@ static void kpatch_compare_sections(struct list_head *seclist) + } + } + ++static enum subsection kpatch_subsection_type(struct section *sec) ++{ ++ if (!strncmp(sec->name, ".text.unlikely.", 15)) ++ return SUBSECTION_UNLIKELY; ++ ++ if (!strncmp(sec->name, ".text.hot.", 10)) ++ return SUBSECTION_HOT; ++ ++ return SUBSECTION_NORMAL; ++} ++ ++static int kpatch_subsection_changed(struct section *sec1, struct section *sec2) ++{ ++ return kpatch_subsection_type(sec1) != kpatch_subsection_type(sec2); ++} ++ + static void kpatch_compare_correlated_symbol(struct symbol *sym) + { + struct symbol *sym1 = sym, *sym2 = sym->twin; +@@ -720,10 +742,12 @@ static void kpatch_compare_correlated_symbol(struct symbol *sym) + /* + * If two symbols are correlated but their sections are not, then the + * symbol has changed sections. This is only allowed if the symbol is +- * moving out of an ignored section. +++ * moving out of an ignored section, or moving between normal/hot/unlikely +++ * subsections. + */ + if (sym1->sec && sym2->sec && sym1->sec->twin != sym2->sec) { +- if (sym2->sec->twin && sym2->sec->twin->ignore) ++ if ((sym2->sec->twin && sym2->sec->twin->ignore) || ++ kpatch_subsection_changed(sym1->sec, sym2->sec)) + sym->status = CHANGED; + else if (sym1->name[0] == '$') /* reserved symbols in aarch64 */ + log_debug("maping symbols: %s", sym1->name); /* do nothing just ignogre */ +-- +2.19.1 + diff --git a/9001-livepatch-patch-hook-don-t-active-patch-when-insmod.patch b/9001-livepatch-patch-hook-don-t-active-patch-when-insmod.patch new file mode 100644 index 0000000..5eb830e --- /dev/null +++ b/9001-livepatch-patch-hook-don-t-active-patch-when-insmod.patch @@ -0,0 +1,34 @@ +From ee167e43252bdb9e84cbefcd8b6fe767c9dc768f Mon Sep 17 00:00:00 2001 +From: Zhipeng Xie +Date: Fri, 2 Nov 2018 17:24:15 +0000 +Subject: [PATCH 1001/1015] livepatch-patch-hook: don't active patch when + insmod + +we want to active patch after loading the patch. + +Signed-off-by: Zhipeng Xie +--- + kmod/patch/livepatch-patch-hook.c | 7 ------- + 1 files changed, 0 insertions(+), 7 deletions(-) + +diff --git a/kmod/patch/livepatch-patch-hook.c b/kmod/patch/livepatch-patch-hook.c +index 7a587a3..e59a377 100644 +--- a/kmod/patch/livepatch-patch-hook.c ++++ b/kmod/patch/livepatch-patch-hook.c +@@ -443,13 +443,6 @@ static int __init patch_init(void) + return ret; + } + +- ret = klp_enable_patch(lpatch); +- if (ret) { +- WARN_ON(klp_unregister_patch(lpatch)); +- patch_free_livepatch(lpatch); +- return ret; +- } +- + return 0; + out: + patch_free_livepatch(lpatch); +-- +1.7.5.4 + diff --git a/9002-kpatch-build-support-third-party-module-make-hotpatc.patch b/9002-kpatch-build-support-third-party-module-make-hotpatc.patch new file mode 100644 index 0000000..aca7798 --- /dev/null +++ b/9002-kpatch-build-support-third-party-module-make-hotpatc.patch @@ -0,0 +1,208 @@ +From c27f1093cd47c48e2f403c4ffb29bf066ce0bea5 Mon Sep 17 00:00:00 2001 +From: Zhipeng Xie +Date: Fri, 2 Nov 2018 17:24:24 +0000 +Subject: [PATCH 1002/1015] kpatch-build: support third party module make + hotpatch + +support out of tree module to make hotpatch. + +Signed-off-by: Zhipeng Xie +--- + kpatch-build/kpatch-build | 76 ++++++++++++++++++++++++++++++++++++--------- + kpatch-build/kpatch-gcc | 5 +++ + 2 files changed, 66 insertions(+), 15 deletions(-) + +diff --git a/kpatch-build/kpatch-build b/kpatch-build/kpatch-build +index a76913f..ccef86d 100755 +--- a/kpatch-build/kpatch-build ++++ b/kpatch-build/kpatch-build +@@ -102,7 +102,11 @@ remove_patches() { + for (( ; APPLIED_PATCHES>0; APPLIED_PATCHES-- )); do + idx=$(( APPLIED_PATCHES - 1)) + patch="${PATCH_LIST[$idx]}" +- patch -p1 -R -d "$SRCDIR" < "$patch" &> /dev/null ++ if [ -n "$USERMODDIR" ];then ++ patch -p1 -R -d "$USERMODDIR" < "$patch" &> /dev/null ++ else ++ patch -p1 -R -d "$SRCDIR" < "$patch" &> /dev/null ++ fi + done + + # If $SRCDIR was a git repo, make sure git actually sees that +@@ -318,8 +322,8 @@ find_parent_obj() { + num="$(grep -l "$grepname" "$last_deep_find"/.*.cmd | grep -Fvc "$pdir/.${file}.cmd")" + fi + if [[ "$num" -eq 0 ]]; then +- parent="$(find ./* -name ".*.cmd" -print0 | xargs -0 grep -l "$grepname" | grep -Fv "$pdir/.${file}.cmd" | cut -c3- | head -n1)" +- num="$(find ./* -name ".*.cmd" -print0 | xargs -0 grep -l "$grepname" | grep -Fvc "$pdir/.${file}.cmd")" ++ parent="$(find . -name ".*.cmd" -print0 | xargs -0 grep -l "$grepname" | grep -Fv "$pdir/.${file}.cmd" | cut -c3- | head -n1)" ++ num="$(find . -name ".*.cmd" -print0 | xargs -0 grep -l "$grepname" | grep -Fvc "$pdir/.${file}.cmd")" + [[ "$num" -eq 1 ]] && last_deep_find="$(dirname "$parent")" + fi + else +@@ -335,6 +339,9 @@ find_parent_obj() { + PARENT="${PARENT#.}" + PARENT="${PARENT%.cmd}" + PARENT="$dir/$PARENT" ++ if [ -n "$USERMODDIR" ];then ++ PARENT="$(readlink -f "$PARENT")" ++ fi + [[ ! -e "$PARENT" ]] && die "ERROR: can't find parent $PARENT for $1" + } + +@@ -397,7 +404,7 @@ usage() { + echo " (not recommended)" >&2 + } + +-options="$(getopt -o ha:r:s:c:v:j:t:n:o:d -l "help,archversion:,sourcerpm:,sourcedir:,config:,vmlinux:,jobs:,target:,name:,output:,debug,skip-gcc-check,skip-cleanup" -- "$@")" || die "getopt failed" ++options="$(getopt -o ha:r:s:c:v:j:t:n:o:dm:b: -l "help,archversion:,sourcerpm:,sourcedir:,config:,vmlinux:,jobs:,target:,name:,output:,debug,skip-gcc-check,skip-cleanup,moduledir,builddir" -- "$@")" || die "getopt failed" + + eval set -- "$options" + +@@ -463,6 +470,16 @@ while [[ $# -gt 0 ]]; do + echo "WARNING: Skipping gcc version matching check (not recommended)" + SKIPGCCCHECK=1 + ;; ++ -m|--moduledir) ++ USERMODDIR=$(readlink -f "$2") ++ shift ++ [[ ! -d "$USERMODDIR" ]] && die "module dir $USERMODDIR not found" ++ ;; ++ -b|--builddir) ++ BUILDDIR=$(readlink -f "$2") ++ shift ++ [[ ! -d "$BUILDDIR" ]] && die "kernel develop dir $BUILDDIR not found" ++ ;; + *) + [[ "$1" = "--" ]] && shift && continue + [[ ! -f "$1" ]] && die "patch file '$1' not found" +@@ -528,7 +545,7 @@ if [[ "$ARCHVERSION" =~ - ]]; then + fi + [[ "$ARCHVERSION" =~ .el7a. ]] && ALT="-alt" + +-[[ -z "$TARGETS" ]] && TARGETS="vmlinux modules" ++[[ -z "$USERMODDIR" ]] && [[ -z "$TARGETS" ]] && TARGETS="vmlinux modules" + + # Don't check external file. + # shellcheck disable=SC1091 +@@ -691,7 +708,11 @@ fi + grep -q "CONFIG_DEBUG_INFO_SPLIT=y" "$CONFIGFILE" && die "kernel option 'CONFIG_DEBUG_INFO_SPLIT' not supported" + + echo "Testing patch file(s)" +-cd "$SRCDIR" || die ++if [ -z "$USERMODDIR" ];then ++ cd "$SRCDIR" || die ++else ++ cd $USERMODDIR || die ++fi + apply_patches + remove_patches + +@@ -709,15 +730,23 @@ find_special_section_data + if [[ $DEBUG -ge 4 ]]; then + export KPATCH_GCC_DEBUG=1 + fi +- +-echo "Building original kernel" +-./scripts/setlocalversion --save-scmversion || die ++if [ -z "$USERMODDIR" ];then ++ echo "Building original kernel" ++ ./scripts/setlocalversion --save-scmversion || die ++else ++ echo "Building original module" ++fi + unset KPATCH_GCC_TEMPDIR + # $TARGETS used as list, no quotes. + # shellcheck disable=SC2086 + CROSS_COMPILE="$TOOLSDIR/kpatch-gcc " make "-j$CPUS" $TARGETS 2>&1 | logger || die + +-echo "Building patched kernel" ++sleep 1 ++if [ -z "$USERMODDIR" ];then ++ echo "Building patched kernel" ++else ++ echo "Building patched module" ++fi + apply_patches + mkdir -p "$TEMPDIR/orig" "$TEMPDIR/patched" + KPATCH_GCC_TEMPDIR="$TEMPDIR" +@@ -739,14 +768,22 @@ if [[ ! -e "$TEMPDIR/changed_objs" ]]; then + die "no changed objects found" + fi + +-grep -q vmlinux "$SRCDIR/Module.symvers" || die "truncated $SRCDIR/Module.symvers file" ++SYMVERS="$SRCDIR/Module.symvers" ++if [ ! -f "$SYMVERS" -a -n "$BUILDDIR" ];then ++ SYMVERS="$BUILDDIR/Module.symvers" ++fi ++grep -q vmlinux "$SYMVERS" || die "truncated $SYMVERS file" + + # Read as words, no quotes. + # shellcheck disable=SC2013 + for i in $(cat "$TEMPDIR/changed_objs") + do + mkdir -p "$TEMPDIR/patched/$(dirname "$i")" || die +- cp -f "$SRCDIR/$i" "$TEMPDIR/patched/$i" || die ++ if [ -z "$USERMODDIR" ];then ++ cp -f "$SRCDIR/$i" "$TEMPDIR/patched/$i" || die ++ else ++ cp -f "$i" "$TEMPDIR/patched/$i" || die ++ fi + done + + echo "Extracting new and modified ELF sections" +@@ -788,7 +825,11 @@ for i in $FILES; do + [[ "$i" = usr/initramfs_data.o ]] && continue + + mkdir -p "output/$(dirname "$i")" +- cd "$SRCDIR" || die ++ if [ -z "$USERMODDIR" ];then ++ cd "$SRCDIR" || die ++ else ++ cd $USERMODDIR || die ++ fi + find_kobj "$i" + cd "$TEMPDIR" || die + if [[ -e "orig/$i" ]]; then +@@ -808,7 +849,7 @@ for i in $FILES; do + # create-diff-object orig.o patched.o parent-name parent-symtab + # Module.symvers patch-mod-name output.o + "$TOOLSDIR"/create-diff-object "orig/$i" "patched/$i" "$KOBJFILE_NAME" \ +- "$SYMTAB" "$SRCDIR/Module.symvers" "${MODNAME//-/_}" \ ++ "$SYMTAB" "$SYMVERS" "${MODNAME//-/_}" \ + "output/$i" 2>&1 | logger 1 + check_pipe_status create-diff-object + # create-diff-object returns 3 if no functional change is found +@@ -871,7 +912,12 @@ fi + + cd "$TEMPDIR/patch" || die + +-KPATCH_BUILD="$SRCDIR" KPATCH_NAME="$MODNAME" \ ++if [ -z "$BUILDDIR" ];then ++ KPATCH_BUILDIR="$SRCDIR" ++else ++ KPATCH_BUILDIR="$BUILDDIR" ++fi ++KPATCH_BUILD="$KPATCH_BUILDIR" KPATCH_NAME="$MODNAME" \ + KBUILD_EXTRA_SYMBOLS="$KBUILD_EXTRA_SYMBOLS" \ + KPATCH_LDFLAGS="$KPATCH_LDFLAGS" \ + make 2>&1 | logger || die +diff --git a/kpatch-build/kpatch-gcc b/kpatch-build/kpatch-gcc +index 2d56da1..21f7e2e 100755 +--- a/kpatch-build/kpatch-gcc ++++ b/kpatch-build/kpatch-gcc +@@ -23,6 +23,11 @@ if [[ "$TOOLCHAINCMD" = "gcc" ]] ; then + [[ "$obj" = */.tmp_mc_*.o ]] && break; + + [[ "$obj" = */.tmp_*.o ]] && obj="${obj/.tmp_/}" ++ ++ if [[ $obj =~ \/\.[0-9]+\.o ]]; then ++ break; ++ fi ++ + case "$obj" in + *.mod.o|\ + *built-in.o|\ +-- +1.7.5.4 + diff --git a/9003-kpatch-build-support-makefile-not-in-third-party-mod.patch b/9003-kpatch-build-support-makefile-not-in-third-party-mod.patch new file mode 100644 index 0000000..544b6d0 --- /dev/null +++ b/9003-kpatch-build-support-makefile-not-in-third-party-mod.patch @@ -0,0 +1,92 @@ +From 214de7459555f3f0461cf4127c55f727ccf473d1 Mon Sep 17 00:00:00 2001 +From: Zhipeng Xie +Date: Fri, 2 Nov 2018 17:24:30 +0000 +Subject: [PATCH 1003/1015] kpatch-build: support makefile not in third party + module source directory + +support makefile not in third party module source directory. +for example: + testmod/build/Makefile + testmod/src/test.c + +Signed-off-by: Zhipeng Xie +--- + kpatch-build/kpatch-build | 32 +++++++++++++++++++++++++++----- + 1 files changed, 27 insertions(+), 5 deletions(-) + +diff --git a/kpatch-build/kpatch-build b/kpatch-build/kpatch-build +index ccef86d..93a0589 100755 +--- a/kpatch-build/kpatch-build ++++ b/kpatch-build/kpatch-build +@@ -311,7 +311,10 @@ find_parent_obj() { + dir="$(dirname "$1")" + absdir="$(readlink -f "$dir")" + pwddir="$(readlink -f .)" +- pdir="${absdir#$pwddir/}" ++ pdir="." ++ if [ "$absdir" != "$pwddir" ];then ++ pdir="${absdir#$pwddir/}" ++ fi + file="$(basename "$1")" + grepname="${1%.o}" + grepname="$grepname\\.o" +@@ -326,6 +329,11 @@ find_parent_obj() { + num="$(find . -name ".*.cmd" -print0 | xargs -0 grep -l "$grepname" | grep -Fvc "$pdir/.${file}.cmd")" + [[ "$num" -eq 1 ]] && last_deep_find="$(dirname "$parent")" + fi ++ if [[ "$num" -eq 0 ]]; then ++ parent="$(find $USERMODBUILDDIR -name ".*.cmd" -print0 | xargs -0 grep -l "$grepname" | grep -Fv "$pdir/.${file}.cmd" | head -n1)" ++ num="$(find $USERMODBUILDDIR -name ".*.cmd" -print0 | xargs -0 grep -l "$grepname" | grep -Fvc "$pdir/.${file}.cmd")" ++ [[ "$num" -eq 1 ]] && last_deep_find="$(dirname "$parent")" ++ fi + else + parent="$(grep -l "$grepname" "$dir"/.*.cmd | grep -Fv "$dir/.${file}.cmd" | head -n1)" + num="$(grep -l "$grepname" "$dir"/.*.cmd | grep -Fvc "$dir/.${file}.cmd")" +@@ -730,16 +738,24 @@ find_special_section_data + if [[ $DEBUG -ge 4 ]]; then + export KPATCH_GCC_DEBUG=1 + fi ++if [ -z "$USERMODBUILDDIR" ];then ++ USERMODBUILDDIR=$USERMODDIR; ++fi + if [ -z "$USERMODDIR" ];then + echo "Building original kernel" + ./scripts/setlocalversion --save-scmversion || die + else + echo "Building original module" ++ [[ -e $USERMODDIR/Module.symvers ]] && cp -f $USERMODDIR/Module.symvers $TEMPDIR/patch/ + fi + unset KPATCH_GCC_TEMPDIR + # $TARGETS used as list, no quotes. + # shellcheck disable=SC2086 +-CROSS_COMPILE="$TOOLSDIR/kpatch-gcc " make "-j$CPUS" $TARGETS 2>&1 | logger || die ++if [ -z "$USERMODDIR" ];then ++ CROSS_COMPILE="$TOOLSDIR/kpatch-gcc " make "-j$CPUS" $TARGETS 2>&1 | logger || die ++else ++ CROSS_COMPILE="$TOOLSDIR/kpatch-gcc " make -C "$USERMODBUILDDIR" M="$USERMODBUILDDIR" "-j$CPUS" $USERMODFLAGS $TARGETS 2>&1 | logger || die ++fi + + sleep 1 + if [ -z "$USERMODDIR" ];then +@@ -753,9 +769,15 @@ KPATCH_GCC_TEMPDIR="$TEMPDIR" + export KPATCH_GCC_TEMPDIR + # $TARGETS used as list, no quotes. + # shellcheck disable=SC2086 +-CROSS_COMPILE="$TOOLSDIR/kpatch-gcc " \ +- KBUILD_MODPOST_WARN=1 \ +- make "-j$CPUS" $TARGETS 2>&1 | logger || die ++if [ -z "$USERMODDIR" ];then ++ CROSS_COMPILE="$TOOLSDIR/kpatch-gcc " \ ++ KBUILD_MODPOST_WARN=1 \ ++ make "-j$CPUS" $TARGETS 2>&1 | logger || die ++else ++ CROSS_COMPILE="$TOOLSDIR/kpatch-gcc " \ ++ KBUILD_MODPOST_WARN=1 \ ++ make -C "$USERMODBUILDDIR" M="$USERMODBUILDDIR" "-j$CPUS" $USERMODFLAGS $TARGETS 2>&1 | logger || die ++fi + + # source.c:(.section+0xFF): undefined reference to `symbol' + grep "undefined reference" "$LOGFILE" | sed -r "s/^.*\`(.*)'$/\\1/" \ +-- +1.7.5.4 + diff --git a/9004-create-diff-object-new-static-var-should-be-included.patch b/9004-create-diff-object-new-static-var-should-be-included.patch new file mode 100644 index 0000000..55e5bb0 --- /dev/null +++ b/9004-create-diff-object-new-static-var-should-be-included.patch @@ -0,0 +1,56 @@ +From fc6b9c5b1b3eb5d59186fe35cc90d3c06b07c537 Mon Sep 17 00:00:00 2001 +From: Zhipeng Xie +Date: Fri, 2 Nov 2018 17:24:36 +0000 +Subject: [PATCH 1004/1015] create-diff-object: new static var should be + included + +Before this patch, only global variables(no referenced) will be +included by kpatch-build. But some macros put some static varibles +in the object file, and no function references it, so they won't +be included by kpatch-build. Because they are changed, the kpatch +will report an error. +This patch includes all new static variables, and this method won't +cause a problem even the new static variables are in unbundled section. + +Signed-off-by: Zhou Chengming +Signed-off-by: Zhipeng Xie +--- + kpatch-build/create-diff-object.c | 15 +++++++++++++++ + 1 files changed, 15 insertions(+), 0 deletions(-) + +diff --git a/kpatch-build/create-diff-object.c b/kpatch-build/create-diff-object.c +index d242d01..6e23295 100644 +--- a/kpatch-build/create-diff-object.c ++++ b/kpatch-build/create-diff-object.c +@@ -1536,6 +1536,20 @@ static void kpatch_include_force_elements(struct kpatch_elf *kelf) + sym->include = 0; + } + ++int kpatch_include_new_static_var(struct kpatch_elf *kelf) ++{ ++ struct symbol *sym; ++ ++ list_for_each_entry(sym, &kelf->symbols, list) { ++ if (sym->status == NEW && ++ sym->type == STT_OBJECT && ++ sym->bind == STB_LOCAL) ++ kpatch_include_symbol(sym); ++ } ++ ++ return 0; ++} ++ + static int kpatch_include_new_globals(struct kpatch_elf *kelf) + { + struct symbol *sym; +@@ -3211,6 +3225,7 @@ int main(int argc, char *argv[]) + callbacks_exist = kpatch_include_callback_elements(kelf_patched); + kpatch_include_force_elements(kelf_patched); + new_globals_exist = kpatch_include_new_globals(kelf_patched); ++ kpatch_include_new_static_var(kelf_patched); + + kpatch_print_changes(kelf_patched); + kpatch_dump_kelf(kelf_patched); +-- +1.7.5.4 + diff --git a/9005-livepatch-fix-use-THIS-modname-as-the-name-of-ddebug.patch b/9005-livepatch-fix-use-THIS-modname-as-the-name-of-ddebug.patch new file mode 100644 index 0000000..ea84d33 --- /dev/null +++ b/9005-livepatch-fix-use-THIS-modname-as-the-name-of-ddebug.patch @@ -0,0 +1,32 @@ +From 858cc1f1ef2565d6ffa539550fc13af7e62863e4 Mon Sep 17 00:00:00 2001 +From: Zhipeng Xie +Date: Fri, 2 Nov 2018 17:24:42 +0000 +Subject: [PATCH 1005/1015] livepatch, fix: use THIS modname as the name of + ddebug_table + +We just want a unique name for every module, so put a _ddebug in +this file as the first of _ddebug array. Then remove path will work +correctly, use the mod->name. + +Suggested-by: Li Bin +Signed-off-by: Zhou Chengming +Signed-off-by: Zhipeng Xie +--- + kmod/patch/livepatch-patch-hook.c | 1 + + 1 files changed, 1 insertions(+), 0 deletions(-) + +diff --git a/kmod/patch/livepatch-patch-hook.c b/kmod/patch/livepatch-patch-hook.c +index e59a377..2c0cadd 100644 +--- a/kmod/patch/livepatch-patch-hook.c ++++ b/kmod/patch/livepatch-patch-hook.c +@@ -452,6 +452,7 @@ out: + + static void __exit patch_exit(void) + { ++ pr_debug("make THIS modname first\n"); + WARN_ON(klp_unregister_patch(lpatch)); + } + +-- +1.7.5.4 + diff --git a/9006-create-diff-object-fix-correlate-static-local-variab.patch b/9006-create-diff-object-fix-correlate-static-local-variab.patch new file mode 100644 index 0000000..83526e1 --- /dev/null +++ b/9006-create-diff-object-fix-correlate-static-local-variab.patch @@ -0,0 +1,50 @@ +From 2f95a0fa6214a97f60a0d5ba4dc0cda152d5c7d4 Mon Sep 17 00:00:00 2001 +From: Zhipeng Xie +Date: Fri, 2 Nov 2018 17:24:51 +0000 +Subject: [PATCH 1006/1015] create-diff-object: fix correlate static local + variables for __param section + +kpatch-build correlate fail when no sections reference +static local variables in __param section, so the static +local variables are incorrectly recognized as a new symbol +and include a incomplete __param section into the patch. +The kernel oops when meet the incomplete __param section. +[ 625.961330] Call Trace: +[ 625.963279] [] ? kernfs_name_hash+0x17/0xd0 +[ 625.965213] [] kernfs_add_one+0x8f/0x150 +[ 625.967120] [] __kernfs_create_file+0x7e/0xa0 +[ 625.969038] [] sysfs_add_file_mode_ns+0x9b/0x160 +[ 625.970912] [] internal_create_group+0xd1/0x250 +[ 625.972755] [] ? add_sysfs_param.isra.3+0x89/0x280 +[ 625.975274] [] sysfs_create_group+0x13/0x20 +[ 625.977108] [] module_param_sysfs_setup+0x94/0xd0 +[ 625.978899] [] load_module+0x2392/0x2bc0 +[ 625.980693] [] ? ddebug_proc_write+0xf0/0xf0 +[ 625.982448] [] ? +copy_module_from_fd.isra.43+0x53/0x150 +[ 625.984187] [] SyS_finit_module+0xa6/0xd0 +[ 625.985926] [] system_call_fastpath+0x1c/0x21 + +Signed-off-by: Zhipeng Xie +--- + kpatch-build/create-diff-object.c | 4 ++++ + 1 files changed, 4 insertions(+), 0 deletions(-) + +diff --git a/kpatch-build/create-diff-object.c b/kpatch-build/create-diff-object.c +index 6e23295..bd7dd37 100644 +--- a/kpatch-build/create-diff-object.c ++++ b/kpatch-build/create-diff-object.c +@@ -925,6 +925,10 @@ static int kpatch_is_normal_static_local(struct symbol *sym) + if (is_special_static(sym)) + return 0; + ++ if (!strncmp(sym->name, "__param_", strlen("__param_")) && ++ !strncmp(sym->sec->name, "__param", strlen("__param"))) ++ return 0; ++ + return 1; + } + +-- +1.7.5.4 + diff --git a/9007-create-diff-object-don-t-create-dynamic-reloc-for-sy.patch b/9007-create-diff-object-don-t-create-dynamic-reloc-for-sy.patch new file mode 100644 index 0000000..298afbc --- /dev/null +++ b/9007-create-diff-object-don-t-create-dynamic-reloc-for-sy.patch @@ -0,0 +1,31 @@ +From 0a92ec9f158340501151bf350050597414affece Mon Sep 17 00:00:00 2001 +From: Zhipeng Xie +Date: Fri, 2 Nov 2018 17:24:58 +0000 +Subject: [PATCH 1007/1015] create-diff-object: don't create dynamic reloc for + symbol exported by patch itself + +when a patch export a new function, ___kcrctab+xxx has a reloc, +use origin reloc to get right symbol version. + +Signed-off-by: Zhipeng Xie +--- + kpatch-build/create-diff-object.c | 3 +++ + 1 files changed, 3 insertions(+), 0 deletions(-) + +diff --git a/kpatch-build/create-diff-object.c b/kpatch-build/create-diff-object.c +index bd7dd37..349e483 100644 +--- a/kpatch-build/create-diff-object.c ++++ b/kpatch-build/create-diff-object.c +@@ -2808,6 +2808,9 @@ static void kpatch_create_intermediate_sections(struct kpatch_elf *kelf, + if (!strcmp(sym_objname, "vmlinux")) + continue; + ++ if (!strcmp(sym_objname, pmod_name)) ++ continue; ++ + external = 1; + } + } +-- +1.7.5.4 + diff --git a/9008-livepatch-patch-hook-support-force-enable-disable-fu.patch b/9008-livepatch-patch-hook-support-force-enable-disable-fu.patch new file mode 100644 index 0000000..33a47a0 --- /dev/null +++ b/9008-livepatch-patch-hook-support-force-enable-disable-fu.patch @@ -0,0 +1,45 @@ +From aaaec2d292b7e1d07c35e07ba92917ee05a4a141 Mon Sep 17 00:00:00 2001 +From: Zhipeng Xie +Date: Fri, 2 Nov 2018 17:25:03 +0000 +Subject: [PATCH 1008/1015] livepatch-patch-hook: support force enable/disable + function + +we use immediate to indicate patch which bypass stack check. + +Signed-off-by: Zhipeng Xie +--- + kmod/patch/livepatch-patch-hook.c | 11 +++++++++++ + 1 files changed, 11 insertions(+), 0 deletions(-) + +diff --git a/kmod/patch/livepatch-patch-hook.c b/kmod/patch/livepatch-patch-hook.c +index 2c0cadd..625ffbd 100644 +--- a/kmod/patch/livepatch-patch-hook.c ++++ b/kmod/patch/livepatch-patch-hook.c +@@ -228,6 +228,16 @@ extern struct kpatch_pre_patch_callback __kpatch_callbacks_pre_patch[], __kpatch + extern struct kpatch_post_patch_callback __kpatch_callbacks_post_patch[], __kpatch_callbacks_post_patch_end[]; + extern struct kpatch_pre_unpatch_callback __kpatch_callbacks_pre_unpatch[], __kpatch_callbacks_pre_unpatch_end[]; + extern struct kpatch_post_unpatch_callback __kpatch_callbacks_post_unpatch[], __kpatch_callbacks_post_unpatch_end[]; ++extern unsigned long __kpatch_force_funcs[], __kpatch_force_funcs_end[]; ++ ++static int patch_is_func_forced(unsigned long addr) ++{ ++ unsigned long *a; ++ for (a = __kpatch_force_funcs; a < __kpatch_force_funcs_end; a++) ++ if (*a == addr) ++ return 1; ++ return 0; ++} + + #ifdef HAVE_CALLBACKS + static int add_callbacks_to_patch_objects(void) +@@ -393,6 +403,7 @@ static int __init patch_init(void) + lfunc = &lfuncs[j]; + lfunc->old_name = func->kfunc->name; + lfunc->new_func = (void *)func->kfunc->new_addr; ++ lfunc->immediate = patch_is_func_forced(lfunc->new_func); + #ifdef HAVE_SYMPOS + lfunc->old_sympos = func->kfunc->sympos; + #else +-- +1.7.5.4 + diff --git a/9009-kmod-kpatch-build-support-build-patch-for-old-kernel.patch b/9009-kmod-kpatch-build-support-build-patch-for-old-kernel.patch new file mode 100644 index 0000000..beecafa --- /dev/null +++ b/9009-kmod-kpatch-build-support-build-patch-for-old-kernel.patch @@ -0,0 +1,349 @@ +From e91d2d2c6778275b16249f7e9d7439018fed70fe Mon Sep 17 00:00:00 2001 +From: Zhipeng Xie +Date: Fri, 2 Nov 2018 17:25:08 +0000 +Subject: [PATCH 1009/1015] kmod/kpatch-build: support build patch for + old kernels + +Forward compatible for old kernels + +Signed-off-by: Zhipeng Xie +--- + kmod/patch/kpatch-macros.h | 48 ++++++++++++++ + kmod/patch/kpatch-patch.h | 4 + + kmod/patch/kpatch.lds.S | 12 ++++ + kmod/patch/livepatch-patch-hook.c | 124 +++++++++++++++++++++++++++++++++++++ + kpatch-build/create-diff-object.c | 8 +++ + 5 files changed, 196 insertions(+), 0 deletions(-) + +diff --git a/kmod/patch/kpatch-macros.h b/kmod/patch/kpatch-macros.h +index a60a267..569a18d 100644 +--- a/kmod/patch/kpatch-macros.h ++++ b/kmod/patch/kpatch-macros.h +@@ -133,4 +133,52 @@ struct kpatch_post_unpatch_callback { + printk(_fmt, ## __VA_ARGS__); \ + }) + ++typedef void (*kpatch_loadcall_t)(void); ++typedef void (*kpatch_unloadcall_t)(void); ++ ++struct kpatch_load { ++ kpatch_loadcall_t fn; ++ char *objname; /* filled in by create-diff-object */ ++}; ++ ++struct kpatch_unload { ++ kpatch_unloadcall_t fn; ++ char *objname; /* filled in by create-diff-object */ ++}; ++ ++/* ++ * KPATCH_LOAD_HOOK macro ++ * ++ * The first line only ensures that the hook being registered has the required ++ * function signature. If not, there is compile error on this line. ++ * ++ * The section line declares a struct kpatch_load to be allocated in a new ++ * .kpatch.hook.load section. This kpatch_load_data symbol is later stripped ++ * by create-diff-object so that it can be declared in multiple objects that ++ * are later linked together, avoiding global symbol collision. Since multiple ++ * hooks can be registered, the .kpatch.hook.load section is a table of struct ++ * kpatch_load elements that will be executed in series by the kpatch core ++ * module at load time, assuming the kernel object (module) is currently ++ * loaded; otherwise, the hook is called when module to be patched is loaded ++ * via the module load notifier. ++ */ ++#define KPATCH_LOAD_HOOK(_fn) \ ++ static inline kpatch_loadcall_t __loadtest(void) { return _fn; } \ ++ struct kpatch_load kpatch_load_data __section(.kpatch.hooks.load) = { \ ++ .fn = _fn, \ ++ .objname = NULL \ ++ }; ++ ++/* ++ * KPATCH_UNLOAD_HOOK macro ++ * ++ * Same as LOAD hook with s/load/unload/ ++ */ ++#define KPATCH_UNLOAD_HOOK(_fn) \ ++ static inline kpatch_unloadcall_t __unloadtest(void) { return _fn; } \ ++ struct kpatch_unload kpatch_unload_data __section(.kpatch.hooks.unload) = { \ ++ .fn = _fn, \ ++ .objname = NULL \ ++ }; ++ + #endif /* __KPATCH_MACROS_H_ */ +diff --git a/kmod/patch/kpatch-patch.h b/kmod/patch/kpatch-patch.h +index 917ea32..4d47d30 100644 +--- a/kmod/patch/kpatch-patch.h ++++ b/kmod/patch/kpatch-patch.h +@@ -59,5 +59,9 @@ struct kpatch_post_unpatch_callback { + void (*callback)(void *obj); + char *objname; + }; ++struct kpatch_patch_hook { ++ void (*hook)(void); ++ char *objname; ++}; + + #endif /* _KPATCH_PATCH_H_ */ +diff --git a/kmod/patch/kpatch.lds.S b/kmod/patch/kpatch.lds.S +index bc5de82..e3c4e97 100644 +--- a/kmod/patch/kpatch.lds.S ++++ b/kmod/patch/kpatch.lds.S +@@ -47,4 +47,16 @@ SECTIONS + __kpatch_force_funcs_end = . ; + QUAD(0); + } ++ .kpatch.hooks.load : { ++ __kpatch_hooks_load = . ; ++ *(.kpatch.hooks.load) ++ __kpatch_hooks_load_end = . ; ++ QUAD(0); ++ } ++ .kpatch.hooks.unload : { ++ __kpatch_hooks_unload = . ; ++ *(.kpatch.hooks.unload) ++ __kpatch_hooks_unload_end = . ; ++ QUAD(0); ++ } + } +diff --git a/kmod/patch/livepatch-patch-hook.c b/kmod/patch/livepatch-patch-hook.c +index 625ffbd..8f7d044 100644 +--- a/kmod/patch/livepatch-patch-hook.c ++++ b/kmod/patch/livepatch-patch-hook.c +@@ -64,6 +64,15 @@ + # define HAVE_CALLBACKS + #endif + ++#ifdef EULER_RELEASE_CODE ++# if EULER_RELEASE_CODE <= EULER_RELEASE_VERSION(2, 3) ++# undef HAVE_SYMPOS ++# undef HAVE_IMMEDIATE ++# undef HAVE_ELF_RELOCS ++# define HAVE_LOADHOOKS ++# endif ++#endif ++ + /* + * There are quite a few similar structures at play in this file: + * - livepatch.h structs prefixed with klp_* +@@ -95,6 +104,11 @@ struct patch_object { + #endif + const char *name; + int funcs_nr, relocs_nr; ++#ifdef HAVE_LOADHOOKS ++ struct list_head hooks_load; ++ struct list_head hooks_unload; ++ int hooks_load_nr, hooks_unload_nr; ++#endif + }; + + struct patch_func { +@@ -107,6 +121,13 @@ struct patch_reloc { + struct kpatch_patch_dynrela *kdynrela; + }; + ++#ifdef HAVE_LOADHOOKS ++struct patch_hook { ++ struct list_head list; ++ struct kpatch_patch_hook *khook; ++}; ++#endif ++ + static struct patch_object *patch_alloc_new_object(const char *name) + { + struct patch_object *object; +@@ -118,6 +139,10 @@ static struct patch_object *patch_alloc_new_object(const char *name) + #ifndef HAVE_ELF_RELOCS + INIT_LIST_HEAD(&object->relocs); + #endif ++#ifdef HAVE_LOADHOOKS ++ INIT_LIST_HEAD(&object->hooks_load); ++ INIT_LIST_HEAD(&object->hooks_unload); ++#endif + if (strcmp(name, "vmlinux")) + object->name = name; + list_add(&object->list, &patch_objects); +@@ -180,6 +205,37 @@ static int patch_add_reloc_to_object(struct kpatch_patch_dynrela *kdynrela) + } + #endif + ++#ifdef HAVE_LOADHOOKS ++static int patch_add_hook_to_object(struct kpatch_patch_hook *khook, bool load) ++{ ++ struct patch_hook *hook; ++ struct patch_object *object; ++ ++ hook = kzalloc(sizeof(*hook), GFP_KERNEL); ++ if (!hook) ++ return -ENOMEM; ++ INIT_LIST_HEAD(&hook->list); ++ hook->khook = khook; ++ ++ object = patch_find_object_by_name(khook->objname); ++ if (!object) { ++ kfree(hook); ++ return -ENOMEM; ++ } ++ ++ if (load) { ++ list_add(&hook->list, &object->hooks_load); ++ object->hooks_load_nr++; ++ } ++ else { ++ list_add(&hook->list, &object->hooks_unload); ++ object->hooks_unload_nr++; ++ } ++ ++ return 0; ++} ++#endif ++ + static void patch_free_scaffold(void) { + struct patch_func *func, *safefunc; + struct patch_object *object, *safeobject; +@@ -217,6 +273,12 @@ static void patch_free_livepatch(struct klp_patch *patch) + if (object->relocs) + kfree(object->relocs); + #endif ++#ifdef HAVE_LOADHOOKS ++ if (object->hooks_load) ++ kfree(object->hooks_load); ++ if (object->hooks_unload) ++ kfree(object->hooks_unload); ++#endif + } + if (patch->objs) + kfree(patch->objs); +@@ -228,6 +290,10 @@ extern struct kpatch_pre_patch_callback __kpatch_callbacks_pre_patch[], __kpatch + extern struct kpatch_post_patch_callback __kpatch_callbacks_post_patch[], __kpatch_callbacks_post_patch_end[]; + extern struct kpatch_pre_unpatch_callback __kpatch_callbacks_pre_unpatch[], __kpatch_callbacks_pre_unpatch_end[]; + extern struct kpatch_post_unpatch_callback __kpatch_callbacks_post_unpatch[], __kpatch_callbacks_post_unpatch_end[]; ++#ifdef HAVE_LOADHOOKS ++extern struct kpatch_patch_hook __kpatch_hooks_load[], __kpatch_hooks_load_end[]; ++extern struct kpatch_patch_hook __kpatch_hooks_unload[], __kpatch_hooks_unload_end[]; ++#endif + extern unsigned long __kpatch_force_funcs[], __kpatch_force_funcs_end[]; + + static int patch_is_func_forced(unsigned long addr) +@@ -347,6 +413,11 @@ static int __init patch_init(void) + struct patch_reloc *reloc; + struct klp_reloc *lrelocs, *lreloc; + #endif ++#ifdef HAVE_LOADHOOKS ++ struct patch_hook *hook; ++ struct kpatch_patch_hook *khook_load, *khook_unload; ++ struct klp_hook *lhooks_load, *lhooks_unload, *lhook; ++#endif + + /* organize functions and relocs by object in scaffold */ + for (kfunc = __kpatch_funcs; +@@ -371,6 +442,24 @@ static int __init patch_init(void) + if (ret) + goto out; + ++#ifdef HAVE_LOADHOOKS ++ for (khook_load = __kpatch_hooks_load; ++ khook_load != __kpatch_hooks_load_end; ++ khook_load++) { ++ ret = patch_add_hook_to_object(khook_load, true); ++ if (ret) ++ goto out; ++ } ++ ++ for (khook_unload = __kpatch_hooks_unload; ++ khook_unload != __kpatch_hooks_unload_end; ++ khook_unload++) { ++ ret = patch_add_hook_to_object(khook_unload, false); ++ if (ret) ++ goto out; ++ } ++#endif ++ + /* past this point, only possible return code is -ENOMEM */ + ret = -ENOMEM; + +@@ -403,12 +492,21 @@ static int __init patch_init(void) + lfunc = &lfuncs[j]; + lfunc->old_name = func->kfunc->name; + lfunc->new_func = (void *)func->kfunc->new_addr; ++#if defined(HAVE_IMMEDIATE) + lfunc->immediate = patch_is_func_forced(lfunc->new_func); ++#endif + #ifdef HAVE_SYMPOS + lfunc->old_sympos = func->kfunc->sympos; + #else + lfunc->old_addr = func->kfunc->old_addr; + #endif ++#ifdef EULER_RELEASE_CODE ++# if EULER_RELEASE_CODE <= EULER_RELEASE_VERSION(2, 3) ++ lfunc->old_size = func->kfunc->old_size; ++ lfunc->new_size = func->kfunc->new_size; ++ lfunc->force = patch_is_func_forced(func->kfunc->new_addr); ++# endif ++#endif + j++; + } + +@@ -439,6 +537,32 @@ static int __init patch_init(void) + lobject->callbacks = object->callbacks; + #endif + ++#ifdef HAVE_LOADHOOKS ++ lhooks_load = kzalloc(sizeof(struct klp_hook) * ++ (object->hooks_load_nr+1), GFP_KERNEL); ++ if (!lhooks_load) ++ goto out; ++ lobject->hooks_load = lhooks_load; ++ j = 0; ++ list_for_each_entry(hook, &object->hooks_load, list) { ++ lhook = &lhooks_load[j]; ++ lhook->hook = hook->khook->hook; ++ j++; ++ } ++ ++ lhooks_unload = kzalloc(sizeof(struct klp_hook) * ++ (object->hooks_unload_nr+1), GFP_KERNEL); ++ if (!lhooks_unload) ++ goto out; ++ lobject->hooks_unload = lhooks_unload; ++ j = 0; ++ list_for_each_entry(hook, &object->hooks_unload, list) { ++ lhook = &lhooks_unload[j]; ++ lhook->hook = hook->khook->hook; ++ j++; ++ } ++#endif ++ + i++; + } + +diff --git a/kpatch-build/create-diff-object.c b/kpatch-build/create-diff-object.c +index 349e483..ed96758 100644 +--- a/kpatch-build/create-diff-object.c ++++ b/kpatch-build/create-diff-object.c +@@ -1463,6 +1463,10 @@ static int kpatch_include_callback_elements(struct kpatch_elf *kelf) + ".rela.kpatch.callbacks.post_patch", + ".rela.kpatch.callbacks.pre_unpatch", + ".rela.kpatch.callbacks.post_unpatch", ++ ".kpatch.hooks.load", ++ ".kpatch.hooks.unload", ++ ".rela.kpatch.hooks.load", ++ ".rela.kpatch.hooks.unload", + NULL, + }; + char **callback_section; +@@ -2921,6 +2925,10 @@ static void kpatch_create_callbacks_objname_rela(struct kpatch_elf *kelf, char * + .offset = offsetof(struct kpatch_pre_unpatch_callback, objname) }, + { .name = ".rela.kpatch.callbacks.post_unpatch", + .offset = offsetof(struct kpatch_post_patch_callback, objname) }, ++ { .name = ".rela.kpatch.hooks.load", ++ .offset = offsetof(struct kpatch_patch_hook, objname) }, ++ { .name = ".rela.kpatch.hooks.unload", ++ .offset = offsetof(struct kpatch_patch_hook, objname) }, + { .name = NULL, .offset = 0 }, + }; + struct callback *callbackp; +-- +1.7.5.4 + diff --git a/9010-kmod-kpatch-build-support-cross-compile-hotpatch-for.patch b/9010-kmod-kpatch-build-support-cross-compile-hotpatch-for.patch new file mode 100644 index 0000000..8c71670 --- /dev/null +++ b/9010-kmod-kpatch-build-support-cross-compile-hotpatch-for.patch @@ -0,0 +1,480 @@ +From be8e5ce9541fc230131be230bd0646c473427895 Mon Sep 17 00:00:00 2001 +From: Zhipeng Xie +Date: Fri, 2 Nov 2018 17:25:20 +0000 +Subject: [PATCH 1010/1015] kmod/kpatch-build: support cross compile hotpatch + for aarch64 + +use R_AARCH64_ABS64 for aarch64, function_ptr_rela and +kpatch_line_macro_change_only are left to implement later. + +Signed-off-by: Zhipeng Xie +--- + kmod/patch/livepatch-patch-hook.c | 16 +++--- + kpatch-build/create-diff-object.c | 98 ++++++++++++++++++++++++++++++---- + kpatch-build/create-kpatch-module.c | 24 ++++++++- + kpatch-build/kpatch-build | 42 ++++++++++++--- + kpatch-build/kpatch-gcc | 4 +- + 5 files changed, 152 insertions(+), 32 deletions(-) + +diff --git a/kmod/patch/livepatch-patch-hook.c b/kmod/patch/livepatch-patch-hook.c +index 8f7d044..ee3b2b9 100644 +--- a/kmod/patch/livepatch-patch-hook.c ++++ b/kmod/patch/livepatch-patch-hook.c +@@ -66,13 +66,17 @@ + + #ifdef EULER_RELEASE_CODE + # if EULER_RELEASE_CODE <= EULER_RELEASE_VERSION(2, 3) +-# undef HAVE_SYMPOS +-# undef HAVE_IMMEDIATE +-# undef HAVE_ELF_RELOCS +-# define HAVE_LOADHOOKS ++# define __HULK__ + # endif + #endif + ++#ifdef __HULK__ ++# undef HAVE_SYMPOS ++# undef HAVE_IMMEDIATE ++# undef HAVE_ELF_RELOCS ++# define HAVE_LOADHOOKS ++#endif ++ + /* + * There are quite a few similar structures at play in this file: + * - livepatch.h structs prefixed with klp_* +@@ -500,12 +504,10 @@ static int __init patch_init(void) + #else + lfunc->old_addr = func->kfunc->old_addr; + #endif +-#ifdef EULER_RELEASE_CODE +-# if EULER_RELEASE_CODE <= EULER_RELEASE_VERSION(2, 3) ++#ifdef __HULK__ + lfunc->old_size = func->kfunc->old_size; + lfunc->new_size = func->kfunc->new_size; + lfunc->force = patch_is_func_forced(func->kfunc->new_addr); +-# endif + #endif + j++; + } +diff --git a/kpatch-build/create-diff-object.c b/kpatch-build/create-diff-object.c +index ed96758..b8d3bb4 100644 +--- a/kpatch-build/create-diff-object.c ++++ b/kpatch-build/create-diff-object.c +@@ -70,6 +70,31 @@ char *childobj; + + enum loglevel loglevel = NORMAL; + ++#ifndef EM_X86_64 ++#define EM_X86_64 62 ++#endif ++ ++#ifndef EM_AARCH64 ++#define EM_AARCH64 183 ++#endif ++ ++#ifndef R_AARCH64_ABS64 ++#define R_AARCH64_NONE 0 ++#define R_AARCH64_ABS64 257 ++#define R_AARCH64_CALL26 283 ++#endif ++ ++static unsigned int arch; ++static unsigned int absolute_rela_type; ++ ++static unsigned int arch_of_elf(Elf *elf) ++{ ++ GElf_Ehdr eh; ++ if (!gelf_getehdr(elf, &eh)) ++ ERROR("gelf_getehdr"); ++ return eh.e_machine; ++} ++ + /******************* + * Data structures + * ****************/ +@@ -635,6 +660,8 @@ static void kpatch_compare_correlated_symbol(struct symbol *sym) + if (sym1->sec && sym2->sec && sym1->sec->twin != sym2->sec) { + if (sym2->sec->twin && sym2->sec->twin->ignore) + sym->status = CHANGED; ++ else if (sym1->name[0] == '$') /* reserved symbols in aarch64 */ ++ log_debug("maping symbols: %s", sym1->name); /* do nothing just ignogre */ + else + DIFF_FATAL("symbol changed sections: %s", sym1->name); + } +@@ -2294,7 +2321,7 @@ static void kpatch_create_kpatch_arch_section(struct kpatch_elf *kelf, char *obj + /* entries[index].sec */ + ALLOC_LINK(rela, &karch_sec->rela->relas); + rela->sym = sec->secsym; +- rela->type = ABSOLUTE_RELA_TYPE; ++ rela->type = absolute_rela_type; + rela->addend = 0; + rela->offset = index * sizeof(*entries) + \ + offsetof(struct kpatch_arch, sec); +@@ -2302,7 +2329,7 @@ static void kpatch_create_kpatch_arch_section(struct kpatch_elf *kelf, char *obj + /* entries[index].objname */ + ALLOC_LINK(rela, &karch_sec->rela->relas); + rela->sym = strsym; +- rela->type = ABSOLUTE_RELA_TYPE; ++ rela->type = absolute_rela_type; + rela->addend = offset_of_string(&kelf->strings, objname); + rela->offset = index * sizeof(*entries) + \ + offsetof(struct kpatch_arch, objname); +@@ -2500,7 +2527,7 @@ static void kpatch_create_patches_sections(struct kpatch_elf *kelf, + */ + ALLOC_LINK(rela, &relasec->relas); + rela->sym = sym; +- rela->type = ABSOLUTE_RELA_TYPE; ++ rela->type = absolute_rela_type; + rela->addend = 0; + rela->offset = index * sizeof(*funcs); + +@@ -2510,7 +2537,7 @@ static void kpatch_create_patches_sections(struct kpatch_elf *kelf, + */ + ALLOC_LINK(rela, &relasec->relas); + rela->sym = strsym; +- rela->type = ABSOLUTE_RELA_TYPE; ++ rela->type = absolute_rela_type; + rela->addend = offset_of_string(&kelf->strings, sym->name); + rela->offset = index * sizeof(*funcs) + + offsetof(struct kpatch_patch_func, name); +@@ -2521,7 +2548,7 @@ static void kpatch_create_patches_sections(struct kpatch_elf *kelf, + */ + ALLOC_LINK(rela, &relasec->relas); + rela->sym = strsym; +- rela->type = ABSOLUTE_RELA_TYPE; ++ rela->type = absolute_rela_type; + rela->addend = objname_offset; + rela->offset = index * sizeof(*funcs) + + offsetof(struct kpatch_patch_func,objname); +@@ -2834,7 +2861,7 @@ static void kpatch_create_intermediate_sections(struct kpatch_elf *kelf, + /* add rela to fill in ksyms[index].name field */ + ALLOC_LINK(rela2, &ksym_sec->rela->relas); + rela2->sym = strsym; +- rela2->type = ABSOLUTE_RELA_TYPE; ++ rela2->type = absolute_rela_type; + rela2->addend = offset_of_string(&kelf->strings, rela->sym->name); + rela2->offset = index * sizeof(*ksyms) + \ + offsetof(struct kpatch_symbol, name); +@@ -2842,7 +2869,7 @@ static void kpatch_create_intermediate_sections(struct kpatch_elf *kelf, + /* add rela to fill in ksyms[index].objname field */ + ALLOC_LINK(rela2, &ksym_sec->rela->relas); + rela2->sym = strsym; +- rela2->type = ABSOLUTE_RELA_TYPE; ++ rela2->type = absolute_rela_type; + rela2->addend = offset_of_string(&kelf->strings, sym_objname); + rela2->offset = index * sizeof(*ksyms) + \ + offsetof(struct kpatch_symbol, objname); +@@ -2863,7 +2890,7 @@ static void kpatch_create_intermediate_sections(struct kpatch_elf *kelf, + ERROR("can't create dynrela for section %s (symbol %s): no bundled or section symbol", + sec->name, rela->sym->name); + +- rela2->type = ABSOLUTE_RELA_TYPE; ++ rela2->type = absolute_rela_type; + rela2->addend = rela->offset; + rela2->offset = index * sizeof(*krelas) + \ + offsetof(struct kpatch_relocation, dest); +@@ -2871,7 +2898,7 @@ static void kpatch_create_intermediate_sections(struct kpatch_elf *kelf, + /* add rela to fill in krelas[index].objname field */ + ALLOC_LINK(rela2, &krela_sec->rela->relas); + rela2->sym = strsym; +- rela2->type = ABSOLUTE_RELA_TYPE; ++ rela2->type = absolute_rela_type; + rela2->addend = offset_of_string(&kelf->strings, objname); + rela2->offset = index * sizeof(*krelas) + \ + offsetof(struct kpatch_relocation, objname); +@@ -2879,7 +2906,7 @@ static void kpatch_create_intermediate_sections(struct kpatch_elf *kelf, + /* add rela to fill in krelas[index].ksym field */ + ALLOC_LINK(rela2, &krela_sec->rela->relas); + rela2->sym = ksym_sec_sym; +- rela2->type = ABSOLUTE_RELA_TYPE; ++ rela2->type = absolute_rela_type; + rela2->addend = index * sizeof(*ksyms); + rela2->offset = index * sizeof(*krelas) + \ + offsetof(struct kpatch_relocation, ksym); +@@ -2946,7 +2973,7 @@ static void kpatch_create_callbacks_objname_rela(struct kpatch_elf *kelf, char * + if (!strcmp(callbackp->name, sec->name)) { + ALLOC_LINK(rela, &sec->relas); + rela->sym = strsym; +- rela->type = ABSOLUTE_RELA_TYPE; ++ rela->type = absolute_rela_type; + rela->addend = objname_offset; + rela->offset = callbackp->offset; + break; +@@ -3000,6 +3027,7 @@ static void kpatch_create_mcount_sections(struct kpatch_elf *kelf) + /* add rela in .rela__mcount_loc to fill in function pointer */ + ALLOC_LINK(rela, &relasec->relas); + rela->sym = sym; ++ if (arch == EM_X86_64) { + rela->type = R_X86_64_64; + rela->addend = 0; + rela->offset = index * sizeof(*funcs); +@@ -3024,6 +3052,37 @@ static void kpatch_create_mcount_sections(struct kpatch_elf *kelf) + rela = list_first_entry(&sym->sec->rela->relas, struct rela, + list); + rela->type = R_X86_64_PC32; ++ } else if (arch == EM_AARCH64) { ++ unsigned int *insnp; ++ rela->type = R_AARCH64_ABS64; ++ /* bl <__fentry__> is the second insn */ ++ rela->addend = 4; ++ rela->offset = index * sizeof(*funcs); ++ ++ newdata = malloc(sym->sec->data->d_size); ++ memcpy(newdata, sym->sec->data->d_buf, sym->sec->data->d_size); ++ sym->sec->data->d_buf = newdata; ++ insnp = newdata; ++ ++ /* ++ * mov x9, x30 ++ * nop //function in .text., so it be replaced with nop by recordmcount ++ * mov x30, x9 ++ */ ++ if (insnp[0] != 0xaa1e03e9 || insnp[1] != 0xd503201f || insnp[2] != 0xaa0903fe) ++ ERROR("%s: unexpected instruction at the start of the function", ++ sym->name); ++ ++ /* change the nop to bl __fentry__ */ ++ insnp[1] = 0x94000000; ++ rela = list_first_entry(&sym->sec->rela->relas, struct rela, ++ list); ++ rela->type = R_AARCH64_CALL26; ++ rela->offset = 4; ++ ++ } else { ++ ERROR("unsupport arch %d\n", arch); ++ } + + index++; + } +@@ -3168,6 +3227,7 @@ int main(int argc, char *argv[]) + char *hint = NULL, *orig_obj, *patched_obj, *parent_name; + char *parent_symtab, *mod_symvers, *patch_name, *output_obj; + struct sym_compare_type *base_locals; ++ char *gcc_add_option, *mlongcall; + + arguments.debug = 0; + argp_parse (&argp, argc, argv, 0, NULL, &arguments); +@@ -3188,6 +3248,13 @@ int main(int argc, char *argv[]) + + kelf_base = kpatch_elf_open(orig_obj); + kelf_patched = kpatch_elf_open(patched_obj); ++ arch = arch_of_elf(kelf_base->elf); ++ if (arch == EM_X86_64) ++ absolute_rela_type = R_X86_64_64; ++ else if (arch == EM_AARCH64) ++ absolute_rela_type = R_AARCH64_ABS64; ++ else ++ ERROR("only arch x86_64 and arm64 be supported\n"); + + kpatch_bundle_symbols(kelf_base); + kpatch_bundle_symbols(kelf_patched); +@@ -3276,7 +3343,14 @@ int main(int argc, char *argv[]) + kpatch_create_callbacks_objname_rela(kelf_out, parent_name); + kpatch_build_strings_section_data(kelf_out); + +- kpatch_create_mcount_sections(kelf_out); ++ gcc_add_option = getenv("GCC_ADD_OPTION"); ++ printf("gcc add option :%s\n", gcc_add_option); ++ mlongcall = strstr(gcc_add_option, "-mlong-calls"); ++ if (arch == EM_AARCH64 && mlongcall) { ++ printf("-mlong-calls found, no need to create mcount section\n"); ++ } else { ++ kpatch_create_mcount_sections(kelf_out); ++ } + + /* + * At this point, the set of output sections and symbols is +diff --git a/kpatch-build/create-kpatch-module.c b/kpatch-build/create-kpatch-module.c +index 67b16b0..9f1c3b9 100644 +--- a/kpatch-build/create-kpatch-module.c ++++ b/kpatch-build/create-kpatch-module.c +@@ -31,6 +31,17 @@ + char *childobj; + enum loglevel loglevel = NORMAL; + ++static unsigned int arch; ++static unsigned int absolute_rela_type; ++ ++static unsigned int arch_of_elf(Elf *elf) ++{ ++ GElf_Ehdr eh; ++ if (!gelf_getehdr(elf, &eh)) ++ ERROR("gelf_getehdr"); ++ return eh.e_machine; ++} ++ + /* + * Create .kpatch.dynrelas from .kpatch.relocations and .kpatch.symbols sections + * +@@ -102,14 +113,14 @@ static void create_dynamic_rela_sections(struct kpatch_elf *kelf, struct section + /* dest */ + ALLOC_LINK(rela, &dynsec->rela->relas); + rela->sym = sym; +- rela->type = R_X86_64_64; ++ rela->type = absolute_rela_type; + rela->addend = dest_offset; + rela->offset = index * sizeof(*dynrelas); + + /* name */ + ALLOC_LINK(rela, &dynsec->rela->relas); + rela->sym = strsec->secsym; +- rela->type = R_X86_64_64; ++ rela->type = absolute_rela_type; + rela->addend = name_offset; + rela->offset = index * sizeof(*dynrelas) + \ + offsetof(struct kpatch_patch_dynrela, name); +@@ -117,7 +128,7 @@ static void create_dynamic_rela_sections(struct kpatch_elf *kelf, struct section + /* objname */ + ALLOC_LINK(rela, &dynsec->rela->relas); + rela->sym = strsec->secsym; +- rela->type = R_X86_64_64; ++ rela->type = absolute_rela_type; + rela->addend = objname_offset; + rela->offset = index * sizeof(*dynrelas) + \ + offsetof(struct kpatch_patch_dynrela, objname); +@@ -200,6 +211,13 @@ int main(int argc, char *argv[]) + childobj = basename(arguments.args[0]); + + kelf = kpatch_elf_open(arguments.args[0]); ++ arch = arch_of_elf(kelf->elf); ++ if (arch == EM_X86_64) ++ absolute_rela_type = R_X86_64_64; ++ else if (arch == EM_AARCH64) ++ absolute_rela_type = R_AARCH64_ABS64; ++ else ++ ERROR("only arch x86_64 and arm64 be supported\n"); + + /* + * Sanity checks: +diff --git a/kpatch-build/kpatch-build b/kpatch-build/kpatch-build +index 93a0589..017604c 100755 +--- a/kpatch-build/kpatch-build ++++ b/kpatch-build/kpatch-build +@@ -384,6 +384,27 @@ find_kobj() { + done + } + ++arch_export() { ++ E_MACHINE=$(od -An -j18 -N2 -d $VMLINUX) ++ if [[ $E_MACHINE -eq 62 ]]; then ++ export ARCH=x86_64 ++ export ARCH_COMPILE= ++ export ENDIAN=little ++ export GCC_ADD_OPTION= ++ elif [[ $E_MACHINE -eq 183 ]]; then ++ export ARCH=arm64 ++ export ARCH_COMPILE=aarch64-linux-gnu- ++ export ENDIAN=little ++ if grep "\-mlong-calls" $SRCDIR/Makefile > /dev/null; then ++ export GCC_ADD_OPTION="-fno-section-anchors -mlong-calls" ++ else ++ export GCC_ADD_OPTION="-fno-section-anchors" ++ fi ++ else ++ die "only support arm64 or x86_64 architecture" ++ fi ++} ++ + # Only allow alphanumerics and '_' and '-' in the module name. Everything else + # is replaced with '-'. Also truncate to 48 chars so the full name fits in the + # kernel's 56-byte module name array. +@@ -725,12 +746,12 @@ apply_patches + remove_patches + + cp -LR "$DATADIR/patch" "$TEMPDIR" || die +- ++arch_export + if [[ "$ARCH" = "ppc64le" ]]; then + ARCH_KCFLAGS="-mcmodel=large -fplugin=$PLUGINDIR/ppc64le-plugin.so" + fi + +-export KCFLAGS="-I$DATADIR/patch -ffunction-sections -fdata-sections $ARCH_KCFLAGS" ++export KCFLAGS="-I$DATADIR/patch -ffunction-sections -fdata-sections $ARCH_KCFLAGS ${GCC_ADD_OPTION}" + + echo "Reading special section data" + find_special_section_data +@@ -752,9 +773,9 @@ unset KPATCH_GCC_TEMPDIR + # $TARGETS used as list, no quotes. + # shellcheck disable=SC2086 + if [ -z "$USERMODDIR" ];then +- CROSS_COMPILE="$TOOLSDIR/kpatch-gcc " make "-j$CPUS" $TARGETS 2>&1 | logger || die ++ CROSS_COMPILE="$TOOLSDIR/kpatch-gcc $ARCH_COMPILE" make "-j$CPUS" $TARGETS 2>&1 | logger || die + else +- CROSS_COMPILE="$TOOLSDIR/kpatch-gcc " make -C "$USERMODBUILDDIR" M="$USERMODBUILDDIR" "-j$CPUS" $USERMODFLAGS $TARGETS 2>&1 | logger || die ++ CROSS_COMPILE="$TOOLSDIR/kpatch-gcc $ARCH_COMPILE" make -C "$USERMODBUILDDIR" M="$USERMODBUILDDIR" "-j$CPUS" $USERMODFLAGS $TARGETS 2>&1 | logger || die + fi + + sleep 1 +@@ -770,11 +791,11 @@ export KPATCH_GCC_TEMPDIR + # $TARGETS used as list, no quotes. + # shellcheck disable=SC2086 + if [ -z "$USERMODDIR" ];then +- CROSS_COMPILE="$TOOLSDIR/kpatch-gcc " \ ++ CROSS_COMPILE="$TOOLSDIR/kpatch-gcc $ARCH_COMPILE" \ + KBUILD_MODPOST_WARN=1 \ + make "-j$CPUS" $TARGETS 2>&1 | logger || die + else +- CROSS_COMPILE="$TOOLSDIR/kpatch-gcc " \ ++ CROSS_COMPILE="$TOOLSDIR/kpatch-gcc $ARCH_COMPILE" \ + KBUILD_MODPOST_WARN=1 \ + make -C "$USERMODBUILDDIR" M="$USERMODBUILDDIR" "-j$CPUS" $USERMODFLAGS $TARGETS 2>&1 | logger || die + fi +@@ -907,6 +928,10 @@ if "$KPATCH_MODULE"; then + export KCPPFLAGS="-D__KPATCH_MODULE__" + fi + ++if grep "hulk" $SRCDIR/Makefile > /dev/null; then ++ export KCPPFLAGS="-D__HULK__ $KCPPFLAGS" ++fi ++ + echo "Building patch module: $MODNAME.ko" + + if [[ -z "$USERSRCDIR" ]] && [[ "$DISTRO" = ubuntu ]]; then +@@ -919,12 +944,12 @@ fi + cd "$TEMPDIR/output" || die + # $KPATCH_LDFLAGS and result of find used as list, no quotes. + # shellcheck disable=SC2086,SC2046 +-ld -r $KPATCH_LDFLAGS -o ../patch/tmp_output.o $(find . -name "*.o") 2>&1 | logger || die ++${ARCH_COMPILE}ld -r $KPATCH_LDFLAGS -o ../patch/tmp_output.o $(find . -name "*.o") 2>&1 | logger || die + + if "$KPATCH_MODULE"; then + # Add .kpatch.checksum for kpatch script + md5sum ../patch/tmp_output.o | awk '{printf "%s\0", $1}' > checksum.tmp || die +- objcopy --add-section .kpatch.checksum=checksum.tmp --set-section-flags .kpatch.checksum=alloc,load,contents,readonly ../patch/tmp_output.o || die ++ ${ARCH_COMPILE}objcopy --add-section .kpatch.checksum=checksum.tmp --set-section-flags .kpatch.checksum=alloc,load,contents,readonly ../patch/tmp_output.o || die + rm -f checksum.tmp + "$TOOLSDIR"/create-kpatch-module "$TEMPDIR"/patch/tmp_output.o "$TEMPDIR"/patch/output.o 2>&1 | logger 1 + check_pipe_status create-kpatch-module +@@ -942,6 +967,7 @@ fi + KPATCH_BUILD="$KPATCH_BUILDIR" KPATCH_NAME="$MODNAME" \ + KBUILD_EXTRA_SYMBOLS="$KBUILD_EXTRA_SYMBOLS" \ + KPATCH_LDFLAGS="$KPATCH_LDFLAGS" \ ++CROSS_COMPILE="$ARCH_COMPILE" \ + make 2>&1 | logger || die + + if ! "$KPATCH_MODULE"; then +diff --git a/kpatch-build/kpatch-gcc b/kpatch-build/kpatch-gcc +index 21f7e2e..be18847 100755 +--- a/kpatch-build/kpatch-gcc ++++ b/kpatch-build/kpatch-gcc +@@ -13,7 +13,7 @@ fi + + declare -a args=("$@") + +-if [[ "$TOOLCHAINCMD" = "gcc" ]] ; then ++if [[ "$TOOLCHAINCMD" = ${ARCH_COMPILE}gcc ]] ; then + while [ "$#" -gt 0 ]; do + if [ "$1" = "-o" ]; then + obj="$2" +@@ -64,7 +64,7 @@ if [[ "$TOOLCHAINCMD" = "gcc" ]] ; then + fi + shift + done +-elif [[ "$TOOLCHAINCMD" = "ld" ]] ; then ++elif [[ "$TOOLCHAINCMD" = ${ARCH_COMPILE}ld ]] ; then + while [ "$#" -gt 0 ]; do + if [ "$1" = "-o" ]; then + obj="$2" +-- +1.7.5.4 + diff --git a/9011-kpatch-build-use-.klp.rela-in-euleros-7.5-kernel.patch b/9011-kpatch-build-use-.klp.rela-in-euleros-7.5-kernel.patch new file mode 100644 index 0000000..58562a4 --- /dev/null +++ b/9011-kpatch-build-use-.klp.rela-in-euleros-7.5-kernel.patch @@ -0,0 +1,48 @@ +From 868a6e4462bebcffa4bf6beea02262823e7dc3a3 Mon Sep 17 00:00:00 2001 +From: Zhipeng Xie +Date: Fri, 2 Nov 2018 17:25:33 +0000 +Subject: [PATCH] kpatch-build: use .klp.rela in euleros 7.5 kernel + +use .klp.rela in euleros 7.5 kernel + +Signed-off-by: Zhipeng Xie +--- + kpatch-build/kpatch-build | 13 +++++++++++-- + 1 files changed, 11 insertions(+), 2 deletions(-) + +diff --git a/kpatch-build/kpatch-build b/kpatch-build/kpatch-build +index fb14850..5a70a44 100755 +--- a/kpatch-build/kpatch-build ++++ b/kpatch-build/kpatch-build +@@ -157,6 +157,15 @@ is_rhel() { + [[ $1 =~ \.el[78]\. ]] + } + ++is_euleros_klp() { ++ if [[ "$1" =~ ^3.10.0-862 ]] ;then ++ if [ $ID == "euleros" ];then ++ return 0; ++ fi ++ fi ++ return 1; ++} ++ + find_dirs() { + if [[ -e "$SCRIPTDIR/create-diff-object" ]]; then + # git repo +@@ -708,10 +717,10 @@ KPATCH_MODULE=true + grep -q "CONFIG_DEBUG_INFO=y" "$CONFIGFILE" || die "kernel doesn't have 'CONFIG_DEBUG_INFO' enabled" + if grep -q "CONFIG_LIVEPATCH=y" "$CONFIGFILE"; then + # The kernel supports livepatch. +- if version_gte "${ARCHVERSION//-*/}" 4.7.0 || is_rhel "$ARCHVERSION"; then ++ if version_gte "${ARCHVERSION//-*/}" 4.7.0 || is_rhel "$ARCHVERSION" || is_euleros_klp "$ARCHVERSION"; then + # Use new .klp.rela. sections + KPATCH_MODULE=false +- if version_gte "${ARCHVERSION//-*/}" 4.9.0 || is_rhel "$ARCHVERSION"; then ++ if version_gte "${ARCHVERSION//-*/}" 4.9.0 || is_rhel "$ARCHVERSION" || is_euleros_klp "$ARCHVERSION"; then + KPATCH_LDFLAGS="--unique=.parainstructions --unique=.altinstructions" + fi + fi +-- +1.7.5.4 + diff --git a/9012-create-diff-object-create-dynamic-relocs-for-changed.patch b/9012-create-diff-object-create-dynamic-relocs-for-changed.patch new file mode 100644 index 0000000..7b27cd4 --- /dev/null +++ b/9012-create-diff-object-create-dynamic-relocs-for-changed.patch @@ -0,0 +1,68 @@ +From 78a13a6091a0d4b1a45fe8f378892a64dece7202 Mon Sep 17 00:00:00 2001 +From: Zhipeng Xie +Date: Fri, 2 Nov 2018 17:25:38 +0000 +Subject: [PATCH 1012/1015] create-diff-object: create dynamic relocs for + changed functions in this object + +Currently, we only create dynamic relocs for changed functions of +other objects, but not this object. It will cause a problem like: + +original: funcA and funcB (funcA calls funcB) +patch-1: funcA-1 and funcB-1 (funcA-1 calls funcB-1) +patch-2: funcB-2 (funcA-1 should call funcB-2) + +But as we don't create dynamic relocs for funcA-1, it will call +funcB-1 directly (not by jumping from funcB). So the new funcB-2 +will not get called. This patch will create dynamic relocs for +all the changed functions, including changed ones in this object. + +Reported-by: Xie Zhipeng +Tested-by: Zhou Chengming +Signed-off-by: Zhou Chengming +Signed-off-by: Li Bin +Signed-off-by: Zhipeng Xie +--- + kpatch-build/create-diff-object.c | 20 ++++++++++++++++---- + 1 files changed, 16 insertions(+), 4 deletions(-) + +diff --git a/kpatch-build/create-diff-object.c b/kpatch-build/create-diff-object.c +index b8d3bb4..4fb27da 100644 +--- a/kpatch-build/create-diff-object.c ++++ b/kpatch-build/create-diff-object.c +@@ -2684,6 +2684,14 @@ static void kpatch_create_intermediate_sections(struct kpatch_elf *kelf, + */ + if (may_need_dynrela(rela)) + toc_rela(rela)->need_dynrela = 1; ++ if (rela->sym->sec) { ++ if (rela->sym->type == STT_FUNC && ++ rela->sym->status == CHANGED && ++ rela->sym->sec != sec->base && ++ sec->base->sym && ++ sec->base->sym->type == STT_FUNC) ++ toc_rela(rela)->need_dynrela = 1; ++ } + } + } + +@@ -2765,10 +2773,14 @@ static void kpatch_create_intermediate_sections(struct kpatch_elf *kelf, + /* An unchanged local symbol */ + ret = lookup_local_symbol(table, + rela->sym->name, &result); +- if (ret) +- ERROR("lookup_local_symbol %s needed for %s", +- rela->sym->name, sec->base->name); +- ++ if (ret) { ++ /* maybe it is a global symbol converted in kpatch_create_patches_sections*/ ++ ret = lookup_global_symbol(table, ++ rela->sym->name, &result); ++ if (ret) ++ ERROR("lookup_local_symbol %s needed for %s", ++ rela->sym->name, sec->base->name); ++ } + } + else if (vmlinux) { + /* +-- +1.7.5.4 + diff --git a/9013-kmod-kpatch-build-fix-duplicate-symbol-relocation-fo.patch b/9013-kmod-kpatch-build-fix-duplicate-symbol-relocation-fo.patch new file mode 100644 index 0000000..4e2f5b2 --- /dev/null +++ b/9013-kmod-kpatch-build-fix-duplicate-symbol-relocation-fo.patch @@ -0,0 +1,365 @@ +From 1eaabfe01cfae870abd45bfa470caa144f34e74c Mon Sep 17 00:00:00 2001 +From: Zhipeng Xie +Date: Fri, 2 Nov 2018 17:25:45 +0000 +Subject: [PATCH 1013/1015] kmod/kpatch-build: fix duplicate symbol relocation + for hulk kernel + +hulk kernel fix it by find a uniq symbol(ref_name) and +use ref_offset to find the duplicate symbol + +Signed-off-by: Zhipeng Xie +--- + kmod/patch/kpatch-patch.h | 4 ++ + kmod/patch/livepatch-patch-hook.c | 6 ++ + kpatch-build/create-diff-object.c | 44 +++++++++++++++++- + kpatch-build/create-kpatch-module.c | 23 +++++++++- + kpatch-build/kpatch-build | 12 +++++ + kpatch-build/kpatch-intermediate.h | 2 + + kpatch-build/lookup.c | 87 ++++++++++++++++++++++++++++++++++- + kpatch-build/lookup.h | 8 +++ + 8 files changed, 183 insertions(+), 3 deletions(-) + +diff --git a/kmod/patch/kpatch-patch.h b/kmod/patch/kpatch-patch.h +index 4d47d30..2eacb37 100644 +--- a/kmod/patch/kpatch-patch.h ++++ b/kmod/patch/kpatch-patch.h +@@ -30,6 +30,8 @@ struct kpatch_patch_func { + unsigned long sympos; + char *name; + char *objname; ++ char *ref_name; ++ long ref_offset; + }; + + struct kpatch_patch_dynrela { +@@ -41,6 +43,8 @@ struct kpatch_patch_dynrela { + char *objname; + int external; + int addend; ++ char *ref_name; ++ long ref_offset; + }; + + struct kpatch_pre_patch_callback { +diff --git a/kmod/patch/livepatch-patch-hook.c b/kmod/patch/livepatch-patch-hook.c +index ee3b2b9..fefc068 100644 +--- a/kmod/patch/livepatch-patch-hook.c ++++ b/kmod/patch/livepatch-patch-hook.c +@@ -508,6 +508,8 @@ static int __init patch_init(void) + lfunc->old_size = func->kfunc->old_size; + lfunc->new_size = func->kfunc->new_size; + lfunc->force = patch_is_func_forced(func->kfunc->new_addr); ++ lfunc->ref_name= func->kfunc->ref_name; ++ lfunc->ref_offset = func->kfunc->ref_offset; + #endif + j++; + } +@@ -531,6 +533,10 @@ static int __init patch_init(void) + lreloc->name = reloc->kdynrela->name; + lreloc->addend = reloc->kdynrela->addend; + lreloc->external = reloc->kdynrela->external; ++#ifdef __HULK__ ++ lreloc->ref_name = reloc->kdynrela->ref_name; ++ lreloc->ref_offset = reloc->kdynrela->ref_offset; ++#endif + j++; + } + #endif /* HAVE_ELF_RELOCS */ +diff --git a/kpatch-build/create-diff-object.c b/kpatch-build/create-diff-object.c +index 4fb27da..e72f6dd 100644 +--- a/kpatch-build/create-diff-object.c ++++ b/kpatch-build/create-diff-object.c +@@ -2519,6 +2519,29 @@ static void kpatch_create_patches_sections(struct kpatch_elf *kelf, + funcs[index].old_size = result.size; + funcs[index].new_size = sym->sym.st_size; + funcs[index].sympos = result.pos; ++ if (lookup_is_duplicate_symbol(table, sym->name)) { ++ struct lookup_refsym refsym; ++ long offset; ++ ++ if (lookup_ref_symbol(table, sym->name, &refsym)) ++ ERROR("unresolvable ambiguity on symbol %s\n", sym->name); ++ ++ offset = (long)result.value - (long)refsym.value; ++ funcs[index].ref_offset = offset; ++ ++ /* ++ * Add a relocation that will populate ++ * the funcs[index].ref_name field. ++ */ ++ ALLOC_LINK(rela, &relasec->relas); ++ rela->sym = strsym; ++ rela->type = absolute_rela_type; ++ rela->addend = offset_of_string(&kelf->strings, refsym.name); ++ rela->offset = index * sizeof(*funcs) + ++ offsetof(struct kpatch_patch_func, ref_name); ++ ++ } ++ + + /* + * Add a relocation that will populate +@@ -2653,6 +2676,7 @@ static void kpatch_create_intermediate_sections(struct kpatch_elf *kelf, + struct lookup_result result; + char *sym_objname; + int ret, vmlinux, external; ++ long ref_offset; + + vmlinux = !strcmp(objname, "vmlinux"); + +@@ -2860,12 +2884,29 @@ static void kpatch_create_intermediate_sections(struct kpatch_elf *kelf, + log_debug("lookup for %s @ 0x%016lx len %lu\n", + rela->sym->name, result.value, result.size); + ++ ref_offset = 0; + /* Fill in ksyms[index] */ + if (vmlinux) + ksyms[index].src = result.value; +- else ++ else { + /* for modules, src is discovered at runtime */ + ksyms[index].src = 0; ++ if (lookup_is_duplicate_symbol(table, rela->sym->name)) { ++ struct lookup_refsym refsym; ++ ++ if (lookup_ref_symbol(table, rela->sym->name, &refsym)) ++ ERROR("unresolvable ambiguity on symbol %s\n", rela->sym->name); ++ ++ ref_offset = (long)result.value - (long)refsym.value; ++ /* add rela to fill in ref_name field */ ++ ALLOC_LINK(rela2, &krela_sec->rela->relas); ++ rela2->sym = strsym; ++ rela2->type = absolute_rela_type; ++ rela2->addend = offset_of_string(&kelf->strings, refsym.name); ++ rela2->offset = index * sizeof(*krelas) + ++ offsetof(struct kpatch_relocation, ref_name); ++ } ++ } + ksyms[index].pos = result.pos; + ksyms[index].type = rela->sym->type; + ksyms[index].bind = rela->sym->bind; +@@ -2893,6 +2934,7 @@ static void kpatch_create_intermediate_sections(struct kpatch_elf *kelf, + krelas[index].addend = rela->addend; + krelas[index].type = rela->type; + krelas[index].external = external; ++ krelas[index].ref_offset = ref_offset; + + /* add rela to fill in krelas[index].dest field */ + ALLOC_LINK(rela2, &krela_sec->rela->relas); +diff --git a/kpatch-build/create-kpatch-module.c b/kpatch-build/create-kpatch-module.c +index 9f1c3b9..8292dc8 100644 +--- a/kpatch-build/create-kpatch-module.c ++++ b/kpatch-build/create-kpatch-module.c +@@ -57,7 +57,7 @@ static void create_dynamic_rela_sections(struct kpatch_elf *kelf, struct section + struct section *dynsec; + struct symbol *sym; + struct rela *rela; +- int index, nr, offset, dest_offset, objname_offset, name_offset; ++ int index, nr, offset, dest_offset, objname_offset, name_offset, ref_name_offset; + + ksyms = ksymsec->data->d_buf; + krelas = krelasec->data->d_buf; +@@ -109,6 +109,27 @@ static void create_dynamic_rela_sections(struct kpatch_elf *kelf, struct section + dynrelas[index].type = krelas[index].type; + dynrelas[index].external = krelas[index].external; + dynrelas[index].sympos = ksym->pos; ++ dynrelas[index].ref_name = krelas[index].ref_name; ++ dynrelas[index].ref_offset = krelas[index].ref_offset; ++ ++ if (dynrelas[index].ref_offset) ++ { ++ /* Get objname offset */ ++ rela = find_rela_by_offset(krelasec->rela, ++ index * sizeof(*krelas) + offsetof(struct kpatch_relocation, ref_name)); ++ if (!rela) { ++ ERROR("find_rela_by_offset"); ++ } ++ ref_name_offset = rela->addend; ++ /* ref_name */ ++ ALLOC_LINK(rela, &dynsec->rela->relas); ++ rela->sym = strsec->secsym; ++ rela->type = absolute_rela_type; ++ rela->addend = ref_name_offset; ++ rela->offset = index * sizeof(*dynrelas) + \ ++ offsetof(struct kpatch_patch_dynrela, ref_name); ++ ++ } + + /* dest */ + ALLOC_LINK(rela, &dynsec->rela->relas); +diff --git a/kpatch-build/kpatch-build b/kpatch-build/kpatch-build +index 9c40612..80b9607 100755 +--- a/kpatch-build/kpatch-build ++++ b/kpatch-build/kpatch-build +@@ -894,6 +894,18 @@ for i in $FILES; do + KOBJFILE_NAME="${KOBJFILE_NAME/-/_}" + KOBJFILE_PATH="${TEMPDIR}/module/$KOBJFILE" + SYMTAB="${KOBJFILE_PATH}.symtab" ++ unset KCFLAGS ++ remove_patches ++ if [ -z "$USERMODDIR" ];then ++ cd "$SRCDIR" || die ++ CROSS_COMPILE="$ARCH_COMPILE" make "-j$CPUS" ${KOBJFILE} 2>&1 | logger || die ++ else ++ cd "$USERMODDIR" ++ CROSS_COMPILE="$ARCH_COMPILE" make -C "$USERMODBUILDDIR" M="$USERMODBUILDDIR" "-j$CPUS" $USERMODFLAGS $TARGETS 2>&1 | logger || die ++ fi ++ cp ${KOBJFILE} ${KOBJFILE_PATH} ++ apply_patches ++ cd "$TEMPDIR" || die + fi + + eu-readelf -s "$KOBJFILE_PATH" > "$SYMTAB" +diff --git a/kpatch-build/kpatch-intermediate.h b/kpatch-build/kpatch-intermediate.h +index 3dea775..59deed0 100644 +--- a/kpatch-build/kpatch-intermediate.h ++++ b/kpatch-build/kpatch-intermediate.h +@@ -39,6 +39,8 @@ struct kpatch_relocation { + int external; + char *objname; /* object to which this rela applies to */ + struct kpatch_symbol *ksym; ++ char *ref_name; ++ long ref_offset; + }; + + struct kpatch_arch { +diff --git a/kpatch-build/lookup.c b/kpatch-build/lookup.c +index d08c10b..e4677db 100644 +--- a/kpatch-build/lookup.c ++++ b/kpatch-build/lookup.c +@@ -44,6 +44,7 @@ struct object_symbol { + unsigned long size; + char *name; + int type, bind; ++ int sec_index; + }; + + struct export_symbol { +@@ -229,6 +230,7 @@ static void symtab_read(struct lookup_table *table, char *path) + table->obj_syms[i].value = value; + table->obj_syms[i].size = size; + table->obj_syms[i].name = strdup(name); ++ table->obj_syms[i].sec_index = atoi(ndx); + + if (!strcmp(bind, "LOCAL")) { + table->obj_syms[i].bind = STB_LOCAL; +@@ -425,7 +427,90 @@ char *lookup_exported_symbol_objname(struct lookup_table *table, char *name) + return match->objname; + + return NULL; +- } ++} ++ ++int lookup_is_duplicate_symbol(struct lookup_table *table, char *name) ++{ ++ struct object_symbol *sym; ++ int i, count = 0; ++ ++ for_each_obj_symbol(i, sym, table) ++ if (!strcmp(sym->name, name)) { ++ count++; ++ if (count > 1) ++ return 1; ++ } ++ ++ return 0; ++} ++ ++struct object_symbol *lookup_find_symbol_by_name(struct lookup_table *table, char *name) ++{ ++ struct object_symbol *sym; ++ unsigned long pos = 0; ++ int i, match = 0, in_file = 0; ++ ++ if (!table->local_syms) ++ return NULL; ++ ++ for_each_obj_symbol(i, sym, table) { ++ if (sym->bind == STB_LOCAL && !strcmp(sym->name, name)) ++ pos++; ++ ++ if (table->local_syms == sym) { ++ in_file = 1; ++ continue; ++ } ++ ++ if (!in_file) ++ continue; ++ ++ if (sym->type == STT_FILE) ++ break; ++ ++ if (sym->bind == STB_LOCAL && !strcmp(sym->name, name)) { ++ match = 1; ++ break; ++ } ++ } ++ ++ if (!match) { ++ for_each_obj_symbol(i, sym, table) { ++ if ((sym->bind == STB_GLOBAL || sym->bind == STB_WEAK) && ++ !strcmp(sym->name, name)) { ++ return sym; ++ } ++ } ++ return NULL; ++ } ++ ++ return sym; ++} ++ ++int lookup_ref_symbol(struct lookup_table *table, char *name, ++ struct lookup_refsym *refsym) ++{ ++ struct object_symbol *orig_sym, *sym; ++ int i; ++ ++ orig_sym = lookup_find_symbol_by_name(table, name); ++ if (!orig_sym) ++ ERROR("lookup_ref_symbol"); ++ memset(refsym, 0, sizeof(*refsym)); ++ for_each_obj_symbol(i, sym, table) { ++ if (!strcmp(sym->name, name) || sym->type == STT_FILE || ++ sym->sec_index != orig_sym->sec_index) ++ continue; ++ ++ if (!lookup_is_duplicate_symbol(table, sym->name)) { ++ refsym->name = sym->name; ++ refsym->value = sym->value; ++ return 0; ++ } ++ } ++ ++ return 1; ++} + + #if 0 /* for local testing */ + static void find_this(struct lookup_table *table, char *sym, char *hint) +diff --git a/kpatch-build/lookup.h b/kpatch-build/lookup.h +index 420d0f0..5ad9241 100644 +--- a/kpatch-build/lookup.h ++++ b/kpatch-build/lookup.h +@@ -14,6 +14,11 @@ struct sym_compare_type { + int type; + }; + ++struct lookup_refsym { ++ char *name; ++ unsigned long value; ++}; ++ + struct lookup_table *lookup_open(char *symtab_path, char *symvers_path, + char *hint, struct sym_compare_type *locals); + void lookup_close(struct lookup_table *table); +@@ -23,5 +28,8 @@ int lookup_global_symbol(struct lookup_table *table, char *name, + struct lookup_result *result); + int lookup_is_exported_symbol(struct lookup_table *table, char *name); + char *lookup_exported_symbol_objname(struct lookup_table *table, char *name); ++int lookup_is_duplicate_symbol(struct lookup_table *table, char *name); ++int lookup_ref_symbol(struct lookup_table *table, char *name, ++ struct lookup_refsym *refsym); + + #endif /* _LOOKUP_H_ */ +-- +1.7.5.4 + diff --git a/9014-create-diff-object-add-dynamic-reloction-for-functio.patch b/9014-create-diff-object-add-dynamic-reloction-for-functio.patch new file mode 100644 index 0000000..692a415 --- /dev/null +++ b/9014-create-diff-object-add-dynamic-reloction-for-functio.patch @@ -0,0 +1,31 @@ +From 83ecafcda5326baceeb68fba90dc13083ff48fe6 Mon Sep 17 00:00:00 2001 +From: Zhipeng Xie +Date: Fri, 2 Nov 2018 17:25:50 +0000 +Subject: [PATCH 1014/1015] create-diff-object: add dynamic reloction for + function pointer on aarch64 + +implement function_ptr_rela for aarch64. + +Signed-off-by: Zhipeng Xie +--- + kpatch-build/create-diff-object.c | 4 +++- + 1 files changed, 3 insertions(+), 1 deletions(-) + +diff --git a/kpatch-build/create-diff-object.c b/kpatch-build/create-diff-object.c +index e72f6dd..f8f3e15 100644 +--- a/kpatch-build/create-diff-object.c ++++ b/kpatch-build/create-diff-object.c +@@ -2628,7 +2628,9 @@ static int function_ptr_rela(const struct rela *rela) + rela_toc->addend == (int)rela_toc->sym->sym.st_value && + (rela->type == R_X86_64_32S || + rela->type == R_PPC64_TOC16_HA || +- rela->type == R_PPC64_TOC16_LO_DS)); ++ rela->type == R_PPC64_TOC16_LO_DS || ++ rela->type == R_AARCH64_ADR_PREL_PG_HI21 || ++ rela->type == R_AARCH64_ADD_ABS_LO12_NC)); + } + + static int may_need_dynrela(const struct rela *rela) +-- +1.7.5.4 + diff --git a/9015-create-diff-object-exclude-line-only-change-for-arm6.patch b/9015-create-diff-object-exclude-line-only-change-for-arm6.patch new file mode 100644 index 0000000..6ed7af1 --- /dev/null +++ b/9015-create-diff-object-exclude-line-only-change-for-arm6.patch @@ -0,0 +1,106 @@ +From d1bbff5da464148e5d277b601a31d7872b4e376b Mon Sep 17 00:00:00 2001 +From: Zhipeng Xie +Date: Fri, 2 Nov 2018 17:26:00 +0000 +Subject: [PATCH 1015/1015] create-diff-object: exclude line only change for + arm64 + +exclude line only change for arm64 by compare mov instruction +except immediate part. + +Signed-off-by: Zhipeng Xie +--- + kpatch-build/create-diff-object.c | 71 ++++++++++++++++++++++++++++++++++++- + 1 files changed, 70 insertions(+), 1 deletions(-) + +diff --git a/kpatch-build/create-diff-object.c b/kpatch-build/create-diff-object.c +index f8f3e15..12d8bd6 100644 +--- a/kpatch-build/create-diff-object.c ++++ b/kpatch-build/create-diff-object.c +@@ -609,6 +609,68 @@ static int kpatch_line_macro_change_only(struct section *sec) + return 0; + } + #endif ++#define ARM64_INSTR_LEN 4 ++static int arm64_kpatch_line_macro_change_only(struct section *sec) ++{ ++ unsigned long start1, start2, size, offset; ++ struct rela *rela; ++ int lineonly = 0, found; ++ unsigned int mov_imm_mask = ((1<<16) - 1)<<5; ++ ++ if (sec->status != CHANGED || ++ is_rela_section(sec) || ++ !is_text_section(sec) || ++ sec->sh.sh_size != sec->twin->sh.sh_size || ++ !sec->rela || ++ sec->rela->status != SAME) ++ return 0; ++ ++ start1 = (unsigned long)sec->twin->data->d_buf; ++ start2 = (unsigned long)sec->data->d_buf; ++ size = sec->sh.sh_size; ++ for (offset = 0; offset < size; offset += ARM64_INSTR_LEN) { ++ if (!memcmp((void *)start1 + offset, (void *)start2 + offset, ++ ARM64_INSTR_LEN)) ++ continue; ++ ++ /* verify it's a mov immediate to w1 */ ++ if ((*(int *)(start1 + offset) & ~mov_imm_mask) != ++ (*(int *)(start2 + offset) & ~mov_imm_mask)) ++ return 0; ++ ++ found = 0; ++ list_for_each_entry(rela, &sec->rela->relas, list) { ++ if (rela->offset < offset + ARM64_INSTR_LEN) ++ continue; ++ if (rela->string) ++ continue; ++ if (!strncmp(rela->sym->name, "__warned.", 9)) ++ continue; ++ if (!strncmp(rela->sym->name, "warn_slowpath_", 14) || ++ (!strcmp(rela->sym->name, "__warn_printk")) || ++ (!strcmp(rela->sym->name, "__might_sleep")) || ++ (!strcmp(rela->sym->name, "___might_sleep")) || ++ (!strcmp(rela->sym->name, "__might_fault")) || ++ (!strcmp(rela->sym->name, "printk")) || ++ (!strcmp(rela->sym->name, "lockdep_rcu_suspicious"))) { ++ found = 1; ++ break; ++ } ++ return 0; ++ } ++ if (!found) ++ return 0; ++ ++ lineonly = 1; ++ } ++ ++ if (!lineonly) ++ ERROR("no instruction changes detected for changed section %s", ++ sec->name); ++ ++ return 1; ++} ++ + + static void kpatch_compare_sections(struct list_head *seclist) + { +@@ -624,7 +686,14 @@ static void kpatch_compare_sections(struct list_head *seclist) + + /* exclude WARN-only, might_sleep changes */ + list_for_each_entry(sec, seclist, list) { +- if (kpatch_line_macro_change_only(sec)) { ++ int line_only; ++ if (arch == EM_X86_64) ++ line_only = kpatch_line_macro_change_only(sec); ++ else if (arch == EM_AARCH64) ++ line_only = arm64_kpatch_line_macro_change_only(sec); ++ else ++ line_only = 0; ++ if (line_only) { + log_debug("reverting macro / line number section %s status to SAME\n", + sec->name); + sec->status = SAME; +-- +1.7.5.4 + diff --git a/9016-kpatch-build-include-secsym-in-kpatch_mark_ignored_s.patch b/9016-kpatch-build-include-secsym-in-kpatch_mark_ignored_s.patch new file mode 100644 index 0000000..b64f46d --- /dev/null +++ b/9016-kpatch-build-include-secsym-in-kpatch_mark_ignored_s.patch @@ -0,0 +1,31 @@ +From dc771a1789ea3769777228f792f0902f8b0566ba Mon Sep 17 00:00:00 2001 +From: Zhipeng Xie +Date: Thu, 22 Nov 2018 21:06:32 +0000 +Subject: [PATCH] kpatch-build: include secsym in kpatch_mark_ignored_sections + +kpatch_mark_ignored_sections include .rodata.str1.1 section but does +not include its section symbol, causing its section symbol can not be +included any more in kpatch_include_standard_elements. After the +section symbol is freed in kpatch_elf_teardown, we got a segmentation +fault in kpatch_create_intermediate_sections. + +Signed-off-by: Zhipeng Xie +--- + kpatch-build/create-diff-object.c | 1 + + 1 files changed, 1 insertions(+), 0 deletions(-) + +diff --git a/kpatch-build/create-diff-object.c b/kpatch-build/create-diff-object.c +index 2e54960..97ae0d4 100644 +--- a/kpatch-build/create-diff-object.c ++++ b/kpatch-build/create-diff-object.c +@@ -2285,6 +2285,7 @@ static void kpatch_mark_ignored_sections(struct kpatch_elf *kelf) + * from the section data comparison, but this is a simpler way. + */ + strsec->include = 1; ++ strsec->secsym->include = 1; + name = strsec->data->d_buf + rela->addend; + ignoresec = find_section_by_name(&kelf->sections, name); + if (!ignoresec) +-- +1.7.5.4 + diff --git a/9017-support-compile-kpatch-on-aarch64.patch b/9017-support-compile-kpatch-on-aarch64.patch new file mode 100644 index 0000000..fd80a2f --- /dev/null +++ b/9017-support-compile-kpatch-on-aarch64.patch @@ -0,0 +1,124 @@ +From 50782f658313574a530f80d2f4b78fe23488c6c2 Mon Sep 17 00:00:00 2001 +From: Zhipeng Xie +Date: Thu, 20 Dec 2018 04:55:38 +0000 +Subject: [PATCH] support compile kpatch on aarch64 + +delete __x86_64__ to support compile kpatch on aarch64. + +Signed-off-by: Zhipeng Xie +--- + kpatch-build/Makefile | 3 +++ + kpatch-build/create-diff-object.c | 16 +--------------- + 2 files changed, 4 insertions(+), 15 deletions(-) + +diff --git a/kpatch-build/Makefile b/kpatch-build/Makefile +index 232b336..974e0f2 100644 +--- a/kpatch-build/Makefile ++++ b/kpatch-build/Makefile +@@ -12,6 +12,9 @@ SOURCES = create-diff-object.c kpatch-elf.c \ + ifeq ($(ARCH),x86_64) + SOURCES += insn/insn.c insn/inat.c + INSN = insn/insn.o insn/inat.o ++else ifeq ($(ARCH),aarch64) ++SOURCES += insn/insn.c insn/inat.c ++INSN = insn/insn.o insn/inat.o + else ifeq ($(ARCH),ppc64le) + SOURCES += gcc-plugins/ppc64le-plugin.c + PLUGIN = gcc-plugins/ppc64le-plugin.so +diff --git a/kpatch-build/create-diff-object.c b/kpatch-build/create-diff-object.c +index 97ae0d4..80a76a9 100644 +--- a/kpatch-build/create-diff-object.c ++++ b/kpatch-build/create-diff-object.c +@@ -426,7 +426,6 @@ out: + log_debug("section %s has changed\n", sec->name); + } + +-#ifdef __x86_64__ + /* + * Determine if a section has changed only due to a WARN* or might_sleep + * macro call's embedding of the line number into an instruction operand. +@@ -537,7 +536,7 @@ static int kpatch_line_macro_change_only(struct section *sec) + + return 1; + } +-#elif __powerpc64__ ++#if __powerpc64__ + #define PPC_INSTR_LEN 4 + #define PPC_RA_OFFSET 16 + +@@ -603,11 +602,6 @@ static int kpatch_line_macro_change_only(struct section *sec) + + return 1; + } +-#else +-static int kpatch_line_macro_change_only(struct section *sec) +-{ +- return 0; +-} + #endif + #define ARM64_INSTR_LEN 4 + static int arm64_kpatch_line_macro_change_only(struct section *sec) +@@ -1248,7 +1242,6 @@ static void kpatch_compare_correlated_elements(struct kpatch_elf *kelf) + kpatch_compare_symbols(&kelf->symbols); + } + +-#ifdef __x86_64__ + static void rela_insn(struct section *sec, struct rela *rela, struct insn *insn) + { + unsigned long insn_addr, start, end, rela_addr; +@@ -1267,7 +1260,6 @@ static void rela_insn(struct section *sec, struct rela *rela, struct insn *insn) + return; + } + } +-#endif + + /* + * Mangle the relas a little. The compiler will sometimes use section symbols +@@ -1810,7 +1802,6 @@ static int ex_table_group_size(struct kpatch_elf *kelf, int offset) + return size; + } + +-#ifdef __x86_64__ + static int parainstructions_group_size(struct kpatch_elf *kelf, int offset) + { + static int size = 0; +@@ -1845,7 +1836,6 @@ static int smp_locks_group_size(struct kpatch_elf *kelf, int offset) + { + return 4; + } +-#endif + #ifdef __powerpc64__ + static int fixup_entry_group_size(struct kpatch_elf *kelf, int offset) + { +@@ -1921,7 +1911,6 @@ static struct special_section special_sections[] = { + .name = "__bug_table", + .group_size = bug_table_group_size, + }, +-#ifdef __x86_64__ + { + .name = ".smp_locks", + .group_size = smp_locks_group_size, +@@ -1930,7 +1919,6 @@ static struct special_section special_sections[] = { + .name = ".parainstructions", + .group_size = parainstructions_group_size, + }, +-#endif + { + .name = ".fixup", + .group_size = fixup_group_size, +@@ -1939,12 +1927,10 @@ static struct special_section special_sections[] = { + .name = "__ex_table", /* must come after .fixup */ + .group_size = ex_table_group_size, + }, +-#ifdef __x86_64__ + { + .name = ".altinstructions", + .group_size = altinstructions_group_size, + }, +-#endif + #ifdef __powerpc64__ + { + .name = "__ftr_fixup", +-- +2.19.1 + diff --git a/9018-support-c-plus-kernel-module.patch b/9018-support-c-plus-kernel-module.patch new file mode 100644 index 0000000..209cf49 --- /dev/null +++ b/9018-support-c-plus-kernel-module.patch @@ -0,0 +1,828 @@ +From 9d590b5b9fb59c1cd52221feeef2794eb3333571 Mon Sep 17 00:00:00 2001 +From: Zhipeng Xie +Date: Thu, 8 Nov 2018 15:12:06 +0000 +Subject: [PATCH] support c plus kernel module + +support GNU_UNIQUE type symbols. +support .group section corelation. +support symbol name longger than 128 bytes. +fix object size changed error for __FUNCTION__.xxx. +ignore compile warning for third party modules. +support functions have no fentry call. +support all function force enable/disable +fix sym replacing error for aarch64 + +Signed-off-by: Zhipeng Xie +--- + kmod/patch/livepatch-patch-hook.c | 8 ++ + kpatch-build/create-diff-object.c | 161 ++++++++++++++++++++++++----------- + kpatch-build/create-klp-module.c | 27 +++++- + kpatch-build/create-kpatch-module.c | 15 +-- + kpatch-build/kpatch-build | 7 ++- + kpatch-build/kpatch-elf.c | 8 ++- + kpatch-build/kpatch-gcc | 2 +- + kpatch-build/lookup.c | 125 +++++++++++++++++++++++++-- + kpatch-build/lookup.h | 14 ++- + 9 files changed, 287 insertions(+), 80 deletions(-) + +diff --git a/kmod/patch/livepatch-patch-hook.c b/kmod/patch/livepatch-patch-hook.c +index fefc068..ce1c955 100644 +--- a/kmod/patch/livepatch-patch-hook.c ++++ b/kmod/patch/livepatch-patch-hook.c +@@ -497,8 +497,12 @@ static int __init patch_init(void) + lfunc->old_name = func->kfunc->name; + lfunc->new_func = (void *)func->kfunc->new_addr; + #if defined(HAVE_IMMEDIATE) ++#ifdef __ALL_FORCE__ ++ lfunc->immediate = 1; ++#else + lfunc->immediate = patch_is_func_forced(lfunc->new_func); + #endif ++#endif + #ifdef HAVE_SYMPOS + lfunc->old_sympos = func->kfunc->sympos; + #else +@@ -507,7 +511,11 @@ static int __init patch_init(void) + #ifdef __HULK__ + lfunc->old_size = func->kfunc->old_size; + lfunc->new_size = func->kfunc->new_size; ++#ifdef __ALL_FORCE__ ++ lfunc->force = 1; ++#else + lfunc->force = patch_is_func_forced(func->kfunc->new_addr); ++#endif + lfunc->ref_name= func->kfunc->ref_name; + lfunc->ref_offset = func->kfunc->ref_offset; + #endif +diff --git a/kpatch-build/create-diff-object.c b/kpatch-build/create-diff-object.c +index 97ae0d4..8bb650d 100644 +--- a/kpatch-build/create-diff-object.c ++++ b/kpatch-build/create-diff-object.c +@@ -224,6 +224,7 @@ static int is_special_static(struct symbol *sym) + "__func__.", + "_rs.", + "CSWTCH.", ++ "__FUNCTION__.", + NULL, + }; + char **prefix; +@@ -386,7 +387,7 @@ static void kpatch_compare_correlated_nonrela_section(struct section *sec) + { + struct section *sec1 = sec, *sec2 = sec->twin; + +- if (sec1->sh.sh_type != SHT_NOBITS && ++ if (sec1->sh.sh_type != SHT_NOBITS && sec1->sh.sh_type != SHT_GROUP && + memcmp(sec1->data->d_buf, sec2->data->d_buf, sec1->data->d_size)) + sec->status = CHANGED; + else +@@ -400,8 +401,9 @@ static void kpatch_compare_correlated_section(struct section *sec) + /* Compare section headers (must match or fatal) */ + if (sec1->sh.sh_type != sec2->sh.sh_type || + sec1->sh.sh_flags != sec2->sh.sh_flags || +- sec1->sh.sh_addralign != sec2->sh.sh_addralign || +- sec1->sh.sh_entsize != sec2->sh.sh_entsize) ++ sec1->sh.sh_entsize != sec2->sh.sh_entsize || ++ (sec1->sh.sh_addralign != sec2->sh.sh_addralign && ++ strcmp(sec1->name, ".rodata"))) + DIFF_FATAL("%s section header details differ", sec1->name); + + /* Short circuit for mcount sections, we rebuild regardless */ +@@ -763,6 +765,33 @@ static void kpatch_compare_symbols(struct list_head *symlist) + } + } + ++static int kpatch_correlate_group_section(struct list_head *seclist1, struct list_head *seclist2, struct section *sec1, struct section *sec2) ++{ ++ unsigned int *data1, *end1, *data2; ++ struct section *isec1, *isec2; ++ ++ if (sec1->data->d_size != sec2->data->d_size) ++ return 1; ++ data1 = sec1->data->d_buf; ++ data2 = sec2->data->d_buf; ++ end1 = sec1->data->d_buf + sec1->data->d_size; ++ data1++; ++ data2++; ++ while (data1 < end1) { ++ isec1 = find_section_by_index(seclist1, *data1); ++ if (!isec1) ++ ERROR("group section not found"); ++ isec2 = find_section_by_index(seclist2, *data2); ++ if (!isec2) ++ ERROR("group section not found"); ++ if (strcmp(isec1->name, isec2->name)) ++ return 1; ++ data1++; ++ data2++; ++ } ++ return 0; ++} ++ + static void kpatch_correlate_sections(struct list_head *seclist1, struct list_head *seclist2) + { + struct section *sec1, *sec2; +@@ -777,15 +806,18 @@ static void kpatch_correlate_sections(struct list_head *seclist1, struct list_he + sec1->secsym)) + continue; + +- /* +- * Group sections must match exactly to be correlated. +- * Changed group sections are currently not supported. +- */ ++ /* Group section鐨勬牸寮忎负锛 ++ * flag ++ * section index ++ * section index ++ * ... ++ * ++ * 褰揅++浠g爜鍙戠敓淇敼鏃讹紝section index鍙兘浼氬彂鐢熷彉鍖 ++ * 杩欐椂鍊欐垜浠氨姣斿涓涓媠ection index鎵瀵瑰簲鐨剆ection鐨 ++ * name锛屽鏋滅浉鍚岋紝鎴戜滑灏辫涓鸿繖涓や釜group鏄疭AME ++ * */ + if (sec1->sh.sh_type == SHT_GROUP) { +- if (sec1->data->d_size != sec2->data->d_size) +- continue; +- if (memcmp(sec1->data->d_buf, sec2->data->d_buf, +- sec1->data->d_size)) ++ if(kpatch_correlate_group_section(seclist1, seclist2, sec1, sec2)) + continue; + } + sec1->twin = sec2; +@@ -1308,17 +1340,21 @@ static void kpatch_replace_sections_syms(struct kpatch_elf *kelf) + #ifdef __powerpc64__ + add_off = 0; + #else +- if (rela->type == R_X86_64_PC32) { +- struct insn insn; +- rela_insn(sec, rela, &insn); +- add_off = (long)insn.next_byte - +- (long)sec->base->data->d_buf - +- rela->offset; +- } else if (rela->type == R_X86_64_64 || +- rela->type == R_X86_64_32S) +- add_off = 0; +- else +- continue; ++ add_off = 0; ++ if (arch == EM_X86_64) { ++ if (rela->type == R_X86_64_PC32) { ++ struct insn insn; ++ rela_insn(sec, rela, &insn); ++ add_off = (long)insn.next_byte - ++ (long)sec->base->data->d_buf - ++ rela->offset; ++ } else if (rela->type == R_X86_64_64 || ++ rela->type == R_X86_64_32S) ++ add_off = 0; ++ else ++ continue; ++ } ++ /* add_off is always equal to 0 on arm64 */ + #endif + + /* +@@ -1421,17 +1457,6 @@ static void kpatch_verify_patchability(struct kpatch_elf *kelf) + errs++; + } + +- if (sec->status != SAME && sec->grouped) { +- log_normal("changed section %s is part of a section group\n", +- sec->name); +- errs++; +- } +- +- if (sec->sh.sh_type == SHT_GROUP && sec->status == NEW) { +- log_normal("new/changed group sections are not supported\n"); +- errs++; +- } +- + /* + * ensure we aren't including .data.* or .bss.* + * (.data.unlikely and .data.once is ok b/c it only has __warned vars) +@@ -1458,6 +1483,7 @@ static void kpatch_include_section(struct section *sec) + /* Include the section and its section symbol */ + if (sec->include) + return; ++ + sec->include = 1; + if (sec->secsym) + sec->secsym->include = 1; +@@ -1640,7 +1666,7 @@ static void kpatch_include_force_elements(struct kpatch_elf *kelf) + sym->include = 0; + } + +-int kpatch_include_new_static_var(struct kpatch_elf *kelf) ++static int kpatch_include_new_static_var(struct kpatch_elf *kelf) + { + struct symbol *sym; + +@@ -2253,6 +2279,23 @@ static void kpatch_include_debug_sections(struct kpatch_elf *kelf) + } + } + ++static void kpatch_ignore_debug_sections(struct kpatch_elf *kelf) ++{ ++ struct section *sec; ++ ++ /* include all .debug_* sections */ ++ list_for_each_entry(sec, &kelf->sections, list) { ++ if (is_debug_section(sec)) { ++ sec->include = 0; ++ sec->status = SAME; ++ if (!is_rela_section(sec)) { ++ sec->secsym->include = 0; ++ sec->secsym->status = SAME; ++ } ++ } ++ } ++} ++ + static void kpatch_mark_ignored_sections(struct kpatch_elf *kelf) + { + struct section *sec, *strsec, *ignoresec; +@@ -2589,14 +2632,13 @@ static void kpatch_create_patches_sections(struct kpatch_elf *kelf, + funcs[index].old_size = result.size; + funcs[index].new_size = sym->sym.st_size; + funcs[index].sympos = result.pos; +- if (lookup_is_duplicate_symbol(table, sym->name)) { ++ if (lookup_is_duplicate_symbol(table, sym->name, objname, result.pos)) { + struct lookup_refsym refsym; + long offset; + +- if (lookup_ref_symbol(table, sym->name, &refsym)) ++ if (lookup_ref_symbol_offset(table, sym->name, &refsym, objname, &offset)) + ERROR("unresolvable ambiguity on symbol %s\n", sym->name); + +- offset = (long)result.value - (long)refsym.value; + funcs[index].ref_offset = offset; + + /* +@@ -2631,7 +2673,7 @@ static void kpatch_create_patches_sections(struct kpatch_elf *kelf, + ALLOC_LINK(rela, &relasec->relas); + rela->sym = strsym; + rela->type = absolute_rela_type; +- rela->addend = offset_of_string(&kelf->strings, sym->name); ++ rela->addend = offset_of_string(&kelf->strings, strndup(sym->name, KSYM_NAME_LEN-1)); + rela->offset = index * sizeof(*funcs) + + offsetof(struct kpatch_patch_func, name); + +@@ -2780,13 +2822,14 @@ static void kpatch_create_intermediate_sections(struct kpatch_elf *kelf, + */ + if (may_need_dynrela(rela)) + toc_rela(rela)->need_dynrela = 1; ++ + if (rela->sym->sec) { + if (rela->sym->type == STT_FUNC && +- rela->sym->status == CHANGED && +- rela->sym->sec != sec->base && +- sec->base->sym && +- sec->base->sym->type == STT_FUNC) +- toc_rela(rela)->need_dynrela = 1; ++ rela->sym->status == CHANGED && ++ rela->sym->sec != sec->base && ++ sec->base->sym && ++ sec->base->sym->type == STT_FUNC) ++ toc_rela(rela)->need_dynrela = 1; + } + } + } +@@ -2820,6 +2863,7 @@ static void kpatch_create_intermediate_sections(struct kpatch_elf *kelf, + if (!strcmp(sec->name, ".rela.kpatch.funcs") || + !strcmp(sec->name, ".rela.kpatch.dynrelas")) + continue; ++ + list_for_each_entry_safe(rela, safe, &sec->relas, list) { + if (!rela->need_dynrela) + continue; +@@ -2963,13 +3007,12 @@ static void kpatch_create_intermediate_sections(struct kpatch_elf *kelf, + else { + /* for modules, src is discovered at runtime */ + ksyms[index].src = 0; +- if (lookup_is_duplicate_symbol(table, rela->sym->name)) { ++ if (lookup_is_duplicate_symbol(table, rela->sym->name, objname, result.pos)) { + struct lookup_refsym refsym; + +- if (lookup_ref_symbol(table, rela->sym->name, &refsym)) ++ if (lookup_ref_symbol_offset(table, rela->sym->name, &refsym, objname, &ref_offset)) + ERROR("unresolvable ambiguity on symbol %s\n", rela->sym->name); + +- ref_offset = (long)result.value - (long)refsym.value; + /* add rela to fill in ref_name field */ + ALLOC_LINK(rela2, &krela_sec->rela->relas); + rela2->sym = strsym; +@@ -2987,7 +3030,7 @@ static void kpatch_create_intermediate_sections(struct kpatch_elf *kelf, + ALLOC_LINK(rela2, &ksym_sec->rela->relas); + rela2->sym = strsym; + rela2->type = absolute_rela_type; +- rela2->addend = offset_of_string(&kelf->strings, rela->sym->name); ++ rela2->addend = offset_of_string(&kelf->strings, strndup(rela->sym->name, KSYM_NAME_LEN-1)); + rela2->offset = index * sizeof(*ksyms) + \ + offsetof(struct kpatch_symbol, name); + +@@ -3163,6 +3206,9 @@ static void kpatch_create_mcount_sections(struct kpatch_elf *kelf) + * __fentry__" so that ftrace will be happy. + */ + newdata = malloc(sym->sec->data->d_size); ++ if (!newdata) ++ ERROR("malloc"); ++ + memcpy(newdata, sym->sec->data->d_buf, sym->sec->data->d_size); + sym->sec->data->d_buf = newdata; + insn = newdata; +@@ -3186,6 +3232,8 @@ static void kpatch_create_mcount_sections(struct kpatch_elf *kelf) + rela->offset = index * sizeof(*funcs); + + newdata = malloc(sym->sec->data->d_size); ++ if (!newdata) ++ ERROR("malloc"); + memcpy(newdata, sym->sec->data->d_buf, sym->sec->data->d_size); + sym->sec->data->d_buf = newdata; + insnp = newdata; +@@ -3354,6 +3402,8 @@ int main(int argc, char *argv[]) + char *parent_symtab, *mod_symvers, *patch_name, *output_obj; + struct sym_compare_type *base_locals; + char *gcc_add_option, *mlongcall; ++ char *no_profiling_calls; ++ char *kallsyms; + + arguments.debug = 0; + argp_parse (&argp, argc, argv, 0, NULL, &arguments); +@@ -3400,9 +3450,12 @@ int main(int argc, char *argv[]) + return EXIT_STATUS_NO_CHANGE; + } + ++ kallsyms = getenv("KALLSYMS"); ++ if (kallsyms) ++ log_debug("kallsyms file:%s\n", kallsyms); + /* create symbol lookup table */ + base_locals = kpatch_elf_locals(kelf_base); +- lookup = lookup_open(parent_symtab, mod_symvers, hint, base_locals); ++ lookup = lookup_open(parent_symtab, mod_symvers, hint, base_locals, kallsyms); + free(base_locals); + + kpatch_mark_grouped_sections(kelf_patched); +@@ -3420,7 +3473,12 @@ int main(int argc, char *argv[]) + */ + kpatch_mark_ignored_sections(kelf_patched); + kpatch_compare_correlated_elements(kelf_patched); +- kpatch_check_func_profiling_calls(kelf_patched); ++ ++ no_profiling_calls = getenv("NO_PROFILING_CALLS"); ++ if (!no_profiling_calls) ++ kpatch_check_func_profiling_calls(kelf_patched); ++ else ++ log_debug("NO_PROFILING_CALLS set\n"); + kpatch_elf_teardown(kelf_base); + kpatch_elf_free(kelf_base); + +@@ -3430,6 +3488,7 @@ int main(int argc, char *argv[]) + kpatch_include_standard_elements(kelf_patched); + num_changed = kpatch_include_changed_functions(kelf_patched); + kpatch_include_debug_sections(kelf_patched); ++ kpatch_ignore_debug_sections(kelf_patched); + callbacks_exist = kpatch_include_callback_elements(kelf_patched); + kpatch_include_force_elements(kelf_patched); + new_globals_exist = kpatch_include_new_globals(kelf_patched); +@@ -3470,10 +3529,10 @@ int main(int argc, char *argv[]) + kpatch_build_strings_section_data(kelf_out); + + gcc_add_option = getenv("GCC_ADD_OPTION"); +- printf("gcc add option :%s\n", gcc_add_option); ++ log_debug("gcc add option :%s\n", gcc_add_option); + mlongcall = strstr(gcc_add_option, "-mlong-calls"); + if (arch == EM_AARCH64 && mlongcall) { +- printf("-mlong-calls found, no need to create mcount section\n"); ++ log_debug("-mlong-calls found, no need to create mcount section\n"); + } else { + kpatch_create_mcount_sections(kelf_out); + } +diff --git a/kpatch-build/create-klp-module.c b/kpatch-build/create-klp-module.c +index 253704b..7a72afd 100644 +--- a/kpatch-build/create-klp-module.c ++++ b/kpatch-build/create-klp-module.c +@@ -38,7 +38,9 @@ enum loglevel loglevel = NORMAL; + */ + static struct symbol *find_or_add_ksym_to_symbols(struct kpatch_elf *kelf, + struct section *ksymsec, +- char *strings, int offset) ++ char *strings, int offset, ++ char *ref_name, ++ long ref_offset) + { + struct kpatch_symbol *ksyms, *ksym; + struct symbol *sym; +@@ -71,9 +73,14 @@ static struct symbol *find_or_add_ksym_to_symbols(struct kpatch_elf *kelf, + if (!objname) + ERROR("strdup"); + +- snprintf(pos, 32, "%lu", ksym->pos); + /* .klp.sym.objname.name,pos */ +- snprintf(buf, 256, KLP_SYM_PREFIX "%s.%s,%s", objname, name, pos); ++ if (!ref_name) { ++ snprintf(pos, 32, "%lu", ksym->pos); ++ snprintf(buf, 256, KLP_SYM_PREFIX "%s.%s,%s", objname, name, pos); ++ } else { ++ snprintf(pos, 32, "%ld", ref_offset); ++ snprintf(buf, 256, KLP_SYM_PREFIX "%s-%s,%s", objname, ref_name, pos); ++ } + + /* Look for an already allocated symbol */ + list_for_each_entry(sym, &kelf->symbols, list) { +@@ -180,6 +187,7 @@ static void create_klp_relasecs_and_syms(struct kpatch_elf *kelf, struct section + struct rela *rela; + char *objname; + int nr, index, offset, dest_off; ++ char *ref_name; + + krelas = krelasec->data->d_buf; + nr = krelasec->data->d_size / sizeof(*krelas); +@@ -206,6 +214,17 @@ static void create_klp_relasecs_and_syms(struct kpatch_elf *kelf, struct section + if (!objname) + ERROR("strdup"); + ++ /* Get the unique ref_name */ ++ rela = find_rela_by_offset(krelasec->rela, ++ offset + offsetof(struct kpatch_relocation, ref_name)); ++ if (!rela) ++ ref_name = NULL; ++ else { ++ ref_name = strdup(strings + rela->addend); ++ if (!ref_name) ++ ERROR("strdup"); ++ } ++ + /* Get the .kpatch.symbol entry for the rela src */ + rela = find_rela_by_offset(krelasec->rela, + offset + offsetof(struct kpatch_relocation, ksym)); +@@ -213,7 +232,7 @@ static void create_klp_relasecs_and_syms(struct kpatch_elf *kelf, struct section + ERROR("find_rela_by_offset"); + + /* Create (or find) a klp symbol from the rela src entry */ +- sym = find_or_add_ksym_to_symbols(kelf, ksymsec, strings, rela->addend); ++ sym = find_or_add_ksym_to_symbols(kelf, ksymsec, strings, rela->addend, ref_name, krelas[index].ref_offset); + if (!sym) + ERROR("error finding or adding ksym to symtab"); + +diff --git a/kpatch-build/create-kpatch-module.c b/kpatch-build/create-kpatch-module.c +index 8292dc8..3e24b3a 100644 +--- a/kpatch-build/create-kpatch-module.c ++++ b/kpatch-build/create-kpatch-module.c +@@ -112,14 +112,10 @@ static void create_dynamic_rela_sections(struct kpatch_elf *kelf, struct section + dynrelas[index].ref_name = krelas[index].ref_name; + dynrelas[index].ref_offset = krelas[index].ref_offset; + +- if (dynrelas[index].ref_offset) +- { +- /* Get objname offset */ +- rela = find_rela_by_offset(krelasec->rela, +- index * sizeof(*krelas) + offsetof(struct kpatch_relocation, ref_name)); +- if (!rela) { +- ERROR("find_rela_by_offset"); +- } ++ /* Get ref_name offset */ ++ rela = find_rela_by_offset(krelasec->rela, ++ index * sizeof(*krelas) + offsetof(struct kpatch_relocation, ref_name)); ++ if (rela) { + ref_name_offset = rela->addend; + /* ref_name */ + ALLOC_LINK(rela, &dynsec->rela->relas); +@@ -128,9 +124,8 @@ static void create_dynamic_rela_sections(struct kpatch_elf *kelf, struct section + rela->addend = ref_name_offset; + rela->offset = index * sizeof(*dynrelas) + \ + offsetof(struct kpatch_patch_dynrela, ref_name); +- + } +- ++ + /* dest */ + ALLOC_LINK(rela, &dynsec->rela->relas); + rela->sym = sym; +diff --git a/kpatch-build/kpatch-build b/kpatch-build/kpatch-build +index 81a6a44..a860f12 100755 +--- a/kpatch-build/kpatch-build ++++ b/kpatch-build/kpatch-build +@@ -953,6 +953,10 @@ if grep "hulk" $SRCDIR/Makefile > /dev/null; then + export KCPPFLAGS="-D__HULK__ $KCPPFLAGS" + fi + ++if [[ -n "$NO_STACK_CHECK" ]];then ++ export KCPPFLAGS="-D__ALL_FORCE__ $KCPPFLAGS" ++fi ++ + echo "Building patch module: $MODNAME.ko" + + if [[ -z "$USERSRCDIR" ]] && [[ "$DISTRO" = ubuntu ]]; then +@@ -990,6 +994,7 @@ KBUILD_EXTRA_SYMBOLS="$KBUILD_EXTRA_SYMBOLS" \ + KPATCH_LDFLAGS="$KPATCH_LDFLAGS" \ + CROSS_COMPILE="$ARCH_COMPILE" \ + make 2>&1 | logger || die ++${ARCH_COMPILE}strip -g "$TEMPDIR/patch/$MODNAME.ko" + + if ! "$KPATCH_MODULE"; then + if [[ -z "$KPATCH_LDFLAGS" ]]; then +@@ -1019,7 +1024,7 @@ fi + # column containing lines unique to first file. + UNDEFINED=$(comm -23 <(sort -u "${TEMPDIR}"/undefined_references) \ + <(sort -u "${TEMPDIR}"/new_symbols) | tr '\n' ' ') +-[[ ! -z "$UNDEFINED" ]] && die "Undefined symbols: $UNDEFINED" ++[[ -z "$USERMODDIR" ]] && [[ ! -z "$UNDEFINED" ]] && die "Undefined symbols: $UNDEFINED" + + cp -f "$TEMPDIR/patch/$MODNAME.ko" "$BASE" || die + +diff --git a/kpatch-build/kpatch-elf.c b/kpatch-build/kpatch-elf.c +index fcb7161..0794031 100644 +--- a/kpatch-build/kpatch-elf.c ++++ b/kpatch-build/kpatch-elf.c +@@ -700,8 +700,14 @@ void kpatch_reindex_elements(struct kpatch_elf *kelf) + unsigned int index; + + index = 1; /* elf write function handles NULL section 0 */ +- list_for_each_entry(sec, &kelf->sections, list) ++ list_for_each_entry(sec, &kelf->sections, list) { + sec->index = index++; ++ /* ++ * since we exclude .group section, we clear SHF_GROUP ++ * for every section in case of link error. ++ * */ ++ sec->sh.sh_flags &= (~SHF_GROUP); ++ } + + index = 0; + list_for_each_entry(sym, &kelf->symbols, list) { +diff --git a/kpatch-build/kpatch-gcc b/kpatch-build/kpatch-gcc +index be18847..d36e67b 100755 +--- a/kpatch-build/kpatch-gcc ++++ b/kpatch-build/kpatch-gcc +@@ -13,7 +13,7 @@ fi + + declare -a args=("$@") + +-if [[ "$TOOLCHAINCMD" = ${ARCH_COMPILE}gcc ]] ; then ++if [[ "$TOOLCHAINCMD" = ${ARCH_COMPILE}gcc || "$TOOLCHAINCMD" = ${ARCH_COMPILE}g++ ]] ; then + while [ "$#" -gt 0 ]; do + if [ "$1" = "-o" ]; then + obj="$2" +diff --git a/kpatch-build/lookup.c b/kpatch-build/lookup.c +index e4677db..2a728f6 100644 +--- a/kpatch-build/lookup.c ++++ b/kpatch-build/lookup.c +@@ -45,6 +45,7 @@ struct object_symbol { + char *name; + int type, bind; + int sec_index; ++ unsigned long kaddr; + }; + + struct export_symbol { +@@ -238,6 +239,8 @@ static void symtab_read(struct lookup_table *table, char *path) + table->obj_syms[i].bind = STB_GLOBAL; + } else if (!strcmp(bind, "WEAK")) { + table->obj_syms[i].bind = STB_WEAK; ++ } else if (!strcmp(bind, "GNU_UNIQUE")) { ++ table->obj_syms[i].bind = STB_GNU_UNIQUE; + } else { + ERROR("unknown symbol bind %s", bind); + } +@@ -263,6 +266,56 @@ static void symtab_read(struct lookup_table *table, char *path) + fclose(file); + } + ++static void ksymtab_read(struct lookup_table *table, char *path) ++{ ++ FILE *file; ++ struct object_symbol *sym, *sym1, *sym2; ++ unsigned long value; ++ int i, j, idx; ++ char line[256], name[256], type[256], mod[256]; ++ idx = 0; ++ ++ if ((file = fopen(path, "r")) == NULL) ++ ERROR("fopen"); ++ ++ while (fgets(line, 256, file)) { ++ if (sscanf(line, "%lx %s %s [%s]\n", ++ &value, type, name, mod) != 4) ++ continue; ++ ++ if (name[0] == '$') ++ continue; ++ ++ i = idx; ++ for_each_obj_symbol_continue(i, sym, table) { ++ if (!strncmp(sym->name, name, KSYM_NAME_LEN-1)) { ++ sym->kaddr = value; ++ idx = i + 1; ++ break; ++ } ++ } ++ } ++ ++ for_each_obj_symbol(i, sym1, table) { ++ if (sym1->kaddr == 0) ++ continue; ++ for_each_obj_symbol(j, sym2, table) { ++ if (sym2->kaddr == 0) ++ continue; ++ if (sym1 == sym2) ++ continue; ++ if (sym1->sec_index != sym2->sec_index) ++ continue; ++ if ((long)sym1->value - (long)sym2->value == ++ (long)sym1->kaddr - (long)sym2->kaddr) ++ continue; ++ ++ ERROR("base mismatch(symbol offset)"); ++ } ++ } ++ fclose(file); ++} ++ + static void symvers_read(struct lookup_table *table, char *path) + { + FILE *file; +@@ -306,7 +359,8 @@ static void symvers_read(struct lookup_table *table, char *path) + } + + struct lookup_table *lookup_open(char *symtab_path, char *symvers_path, +- char *hint, struct sym_compare_type *locals) ++ char *hint, struct sym_compare_type *locals, ++ char *kallsyms) + { + struct lookup_table *table; + +@@ -317,6 +371,8 @@ struct lookup_table *lookup_open(char *symtab_path, char *symvers_path, + + symtab_read(table, symtab_path); + symvers_read(table, symvers_path); ++ if (kallsyms) ++ ksymtab_read(table, kallsyms); + find_local_syms(table, hint, locals); + + return table; +@@ -343,6 +399,15 @@ int lookup_local_symbol(struct lookup_table *table, char *name, + for_each_obj_symbol(i, sym, table) { + if (sym->bind == STB_LOCAL && !strcmp(sym->name, name)) + pos++; ++ else { ++ /* symbol name longer than KSYM_NAME_LEN will be truncated ++ * by kernel, so we can not find it using its original ++ * name. we need to add pos for symbols which have same ++ * KSYM_NAME_LEN-1 long prefix.*/ ++ if (strlen(name) >= KSYM_NAME_LEN-1 && ++ !strncmp(sym->name, name, KSYM_NAME_LEN-1)) ++ pos++; ++ } + + if (table->local_syms == sym) { + in_file = 1; +@@ -374,15 +439,25 @@ int lookup_global_symbol(struct lookup_table *table, char *name, + struct lookup_result *result) + { + struct object_symbol *sym; ++ unsigned long pos = 0; + int i; + + memset(result, 0, sizeof(*result)); + for_each_obj_symbol(i, sym, table) { +- if ((sym->bind == STB_GLOBAL || sym->bind == STB_WEAK) && ++ /* symbol name longer than KSYM_NAME_LEN will be truncated ++ * by kernel, so we can not find it using its original ++ * name. we need to add pos for symbols which have same ++ * KSYM_NAME_LEN-1 long prefix.*/ ++ if (strlen(name) >= KSYM_NAME_LEN-1 && ++ !strncmp(sym->name, name, KSYM_NAME_LEN-1)) ++ pos++; ++ ++ if ((sym->bind == STB_GLOBAL || sym->bind == STB_WEAK ++ || sym->bind == STB_GNU_UNIQUE) && + !strcmp(sym->name, name)) { + result->value = sym->value; + result->size = sym->size; +- result->pos = 0; /* always 0 for global symbols */ ++ result->pos = pos; + return 0; + } + } +@@ -429,10 +504,12 @@ char *lookup_exported_symbol_objname(struct lookup_table *table, char *name) + return NULL; + } + +-int lookup_is_duplicate_symbol(struct lookup_table *table, char *name) ++int lookup_is_duplicate_symbol(struct lookup_table *table, char *name, ++ char *objname, unsigned long pos) + { + struct object_symbol *sym; + int i, count = 0; ++ char posstr[32], buf[256]; + + for_each_obj_symbol(i, sym, table) + if (!strcmp(sym->name, name)) { +@@ -441,6 +518,17 @@ int lookup_is_duplicate_symbol(struct lookup_table *table, char *name) + return 1; + } + ++ /* symbol name longer than KSYM_NAME_LEN will be truncated ++ * by kernel, so we can not find it using its original ++ * name. Here, we consider these long name symbol as duplicated ++ * symbols. since create_klp_module will create symbol name ++ * format like .klp.sym.objname.symbol,pos, so we consider name ++ * length longer than KSYM_NAME_LEN-1 bytes as duplicated symbol*/ ++ snprintf(posstr, 32, "%lu", pos); ++ snprintf(buf, 256, KLP_SYM_PREFIX "%s.%s,%s", objname, name, posstr); ++ if (strlen(buf) >= KSYM_NAME_LEN-1) ++ return 1; ++ + return 0; + } + +@@ -487,24 +575,45 @@ struct object_symbol *lookup_find_symbol_by_name(struct lookup_table *table, cha + return sym; + } + +-int lookup_ref_symbol(struct lookup_table *table, char *name, +- struct lookup_refsym *refsym) ++int lookup_ref_symbol_offset(struct lookup_table *table, char *name, ++ struct lookup_refsym *refsym, ++ char *objname, long *offset) + { + struct object_symbol *orig_sym, *sym; + int i; + + orig_sym = lookup_find_symbol_by_name(table, name); + if (!orig_sym) +- ERROR("lookup_ref_symbol"); ++ ERROR("lookup_ref_symbol_offset"); + memset(refsym, 0, sizeof(*refsym)); ++ ++ /*find a unique symbol in the same section first*/ + for_each_obj_symbol(i, sym, table) { + if (!strcmp(sym->name, name) || sym->type == STT_FILE || + sym->sec_index != orig_sym->sec_index) + continue; + +- if (!lookup_is_duplicate_symbol(table, sym->name)) { ++ if (!lookup_is_duplicate_symbol(table, sym->name, objname, 1)) { + refsym->name = sym->name; + refsym->value = sym->value; ++ *offset = (long)orig_sym->value - (long)sym->value; ++ return 0; ++ } ++ } ++ ++ if (orig_sym->kaddr == 0) ++ return 1; ++ ++ /*find a unique symbol has kaddr*/ ++ for_each_obj_symbol(i, sym, table) { ++ if (!strcmp(sym->name, name) || sym->type == STT_FILE || ++ sym->kaddr == 0) ++ continue; ++ ++ if (!lookup_is_duplicate_symbol(table, sym->name, objname, 1)) { ++ refsym->name = sym->name; ++ refsym->value = 0; ++ *offset = (long)orig_sym->kaddr - (long)sym->kaddr; + return 0; + } + } +diff --git a/kpatch-build/lookup.h b/kpatch-build/lookup.h +index 5ad9241..00b6ccc 100644 +--- a/kpatch-build/lookup.h ++++ b/kpatch-build/lookup.h +@@ -1,6 +1,9 @@ + #ifndef _LOOKUP_H_ + #define _LOOKUP_H_ + ++#include "kpatch-elf.h" ++#define KSYM_NAME_LEN 128 ++ + struct lookup_table; + + struct lookup_result { +@@ -20,7 +23,8 @@ struct lookup_refsym { + }; + + struct lookup_table *lookup_open(char *symtab_path, char *symvers_path, +- char *hint, struct sym_compare_type *locals); ++ char *hint, struct sym_compare_type *locals, ++ char *kallsyms); + void lookup_close(struct lookup_table *table); + int lookup_local_symbol(struct lookup_table *table, char *name, + struct lookup_result *result); +@@ -28,8 +32,10 @@ int lookup_global_symbol(struct lookup_table *table, char *name, + struct lookup_result *result); + int lookup_is_exported_symbol(struct lookup_table *table, char *name); + char *lookup_exported_symbol_objname(struct lookup_table *table, char *name); +-int lookup_is_duplicate_symbol(struct lookup_table *table, char *name); +-int lookup_ref_symbol(struct lookup_table *table, char *name, +- struct lookup_refsym *refsym); ++int lookup_is_duplicate_symbol(struct lookup_table *table, char *name, ++ char *objname, unsigned long pos); ++int lookup_ref_symbol_offset(struct lookup_table *table, char *name, ++ struct lookup_refsym *refsym, char *objname, ++ long *offset); + + #endif /* _LOOKUP_H_ */ +-- +1.7.5.4 + diff --git a/9019-fix-rodata.str-problem.patch b/9019-fix-rodata.str-problem.patch new file mode 100644 index 0000000..f356ed3 --- /dev/null +++ b/9019-fix-rodata.str-problem.patch @@ -0,0 +1,28 @@ +From e617351fafaf7504a531fd00a49994653e59a737 Mon Sep 17 00:00:00 2001 +From: Zhiyu Hu +Date: Fri, 28 Dec 2018 07:06:38 +0000 +Subject: [PATCH] fix rodata.str problem + + fix some rodata.str problem + + Signed-off-by: Zhiyu Hu +--- + kpatch-build/create-diff-object.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/kpatch-build/create-diff-object.c b/kpatch-build/create-diff-object.c +index d2e6aee..f075671 100644 +--- a/kpatch-build/create-diff-object.c ++++ b/kpatch-build/create-diff-object.c +@@ -1552,7 +1552,7 @@ static void kpatch_include_standard_elements(struct kpatch_elf *kelf) + !strcmp(sec->name, ".toc") || + !strcmp(sec->name, ".rodata") || + (!strncmp(sec->name, ".rodata.", 8) && +- strstr(sec->name, ".str1."))) { ++ strstr(sec->name, ".str"))) { + kpatch_include_section(sec); + } + } +-- +1.8.3.1 + diff --git a/9023-kpatch-build-adapt-for-ksymtab-in-4.19-kernel.patch b/9023-kpatch-build-adapt-for-ksymtab-in-4.19-kernel.patch new file mode 100644 index 0000000..e655cf5 --- /dev/null +++ b/9023-kpatch-build-adapt-for-ksymtab-in-4.19-kernel.patch @@ -0,0 +1,28 @@ +From f221fbe8ff0c22b61aaf42687f5ece04f10ec403 Mon Sep 17 00:00:00 2001 +From: Zhipeng Xie +Date: Thu, 17 Jan 2019 20:50:25 +0000 +Subject: [PATCH] kpatch-build: adapt for ksymtab in 4.19 kernel + +Signed-off-by: Zhipeng Xie +--- + kpatch-build/create-diff-object.c | 4 ++-- + 1 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/kpatch-build/create-diff-object.c b/kpatch-build/create-diff-object.c +index f075671..2ddd00d 100644 +--- a/kpatch-build/create-diff-object.c ++++ b/kpatch-build/create-diff-object.c +@@ -1664,8 +1664,8 @@ static int kpatch_include_new_static_var(struct kpatch_elf *kelf) + + list_for_each_entry(sym, &kelf->symbols, list) { + if (sym->status == NEW && +- sym->type == STT_OBJECT && +- sym->bind == STB_LOCAL) ++ sym->bind == STB_LOCAL && ++ (sym->type == STT_OBJECT || (sym->type == STT_NOTYPE && sym->name[0] != '$'))) + kpatch_include_symbol(sym); + } + +-- +1.7.5.4 + diff --git a/9024-support-force-enable-disable-for-kernel-4.19.patch b/9024-support-force-enable-disable-for-kernel-4.19.patch new file mode 100644 index 0000000..35727aa --- /dev/null +++ b/9024-support-force-enable-disable-for-kernel-4.19.patch @@ -0,0 +1,91 @@ +From 6b7ff79bb40a7dbb28e6aba320e4ac075e4c182d Mon Sep 17 00:00:00 2001 +From: Zhipeng Xie +Date: Fri, 18 Jan 2019 00:07:02 +0000 +Subject: [PATCH] support force enable/disable for kernel 4.19 + +Signed-off-by: Zhipeng Xie +--- + kmod/patch/livepatch-patch-hook.c | 7 +++++-- + kpatch-build/kpatch-build | 12 ++++++++++-- + 2 files changed, 15 insertions(+), 4 deletions(-) + +diff --git a/kmod/patch/livepatch-patch-hook.c b/kmod/patch/livepatch-patch-hook.c +index ce1c955..919dfc7 100644 +--- a/kmod/patch/livepatch-patch-hook.c ++++ b/kmod/patch/livepatch-patch-hook.c +@@ -511,14 +511,17 @@ static int __init patch_init(void) + #ifdef __HULK__ + lfunc->old_size = func->kfunc->old_size; + lfunc->new_size = func->kfunc->new_size; ++ lfunc->ref_name= func->kfunc->ref_name; ++ lfunc->ref_offset = func->kfunc->ref_offset; ++#endif ++#if defined(__HULK__) || defined(__KLP_SUPPORT_FORCE__) + #ifdef __ALL_FORCE__ + lfunc->force = 1; + #else + lfunc->force = patch_is_func_forced(func->kfunc->new_addr); + #endif +- lfunc->ref_name= func->kfunc->ref_name; +- lfunc->ref_offset = func->kfunc->ref_offset; + #endif ++ + j++; + } + +diff --git a/kpatch-build/kpatch-build b/kpatch-build/kpatch-build +index a860f12..c227b44 100755 +--- a/kpatch-build/kpatch-build ++++ b/kpatch-build/kpatch-build +@@ -279,7 +279,7 @@ find_special_section_data() { + # shellcheck disable=SC2086 + SPECIAL_VARS="$(readelf -wi "$VMLINUX" | + gawk --non-decimal-data $AWK_OPTIONS ' +- BEGIN { a = b = p = e = o = 0 } ++ BEGIN { a = b = p = e = o = f = 0 } + + # Set state if name matches + a == 0 && /DW_AT_name.* alt_instr[[:space:]]*$/ {a = 1; next} +@@ -287,6 +287,7 @@ find_special_section_data() { + p == 0 && /DW_AT_name.* paravirt_patch_site[[:space:]]*$/ {p = 1; next} + e == 0 && /DW_AT_name.* exception_table_entry[[:space:]]*$/ {e = 1; next} + o == 0 && /DW_AT_name.* orc_entry[[:space:]]*$/ {o = 1; next} ++ f == 0 && /DW_AT_name.* klp_func[[:space:]]*$/ {f = 1; next} + + # Reset state unless this abbrev describes the struct size + a == 1 && !/DW_AT_byte_size/ { a = 0; next } +@@ -294,6 +295,8 @@ find_special_section_data() { + p == 1 && !/DW_AT_byte_size/ { p = 0; next } + e == 1 && !/DW_AT_byte_size/ { e = 0; next } + o == 1 && !/DW_AT_byte_size/ { o = 0; next } ++ f == 1 && /DW_TAG_structure_type/ { f = 3; next } ++ f == 1 && /DW_AT_name.* force[[:space:]]*$/ {f = 2; next} + + # Now that we know the size, stop parsing for it + a == 1 {printf("export ALT_STRUCT_SIZE=%d\n", $4); a = 2} +@@ -301,9 +304,10 @@ find_special_section_data() { + p == 1 {printf("export PARA_STRUCT_SIZE=%d\n", $4); p = 2} + e == 1 {printf("export EX_STRUCT_SIZE=%d\n", $4); e = 2} + o == 1 {printf("export ORC_STRUCT_SIZE=%d\n", $4); o = 2} ++ f == 2 {printf("export KLP_SUPPORT_FORCE=y\n"); f = 3} + + # Bail out once we have everything +- a == 2 && b == 2 && (p == 2 || skip_p) && e == 2 && (o == 2 || skip_o) {exit}')" ++ a == 2 && b == 2 && (p == 2 || skip_p) && e == 2 && (o == 2 || skip_o) && f == 3 {exit}')" + + [[ -n "$SPECIAL_VARS" ]] && eval "$SPECIAL_VARS" + +@@ -957,6 +961,10 @@ if [[ -n "$NO_STACK_CHECK" ]];then + export KCPPFLAGS="-D__ALL_FORCE__ $KCPPFLAGS" + fi + ++if [[ -n "$KLP_SUPPORT_FORCE" ]];then ++ export KCPPFLAGS="-D__KLP_SUPPORT_FORCE__ $KCPPFLAGS" ++fi ++ + echo "Building patch module: $MODNAME.ko" + + if [[ -z "$USERSRCDIR" ]] && [[ "$DISTRO" = ubuntu ]]; then +-- +1.7.5.4 + diff --git a/9025-kpatch-build-adapt-for-native-compile_env.patch b/9025-kpatch-build-adapt-for-native-compile_env.patch new file mode 100644 index 0000000..e2f5857 --- /dev/null +++ b/9025-kpatch-build-adapt-for-native-compile_env.patch @@ -0,0 +1,118 @@ +From 87203483495fec8ad1394def83fa884a96b711ec Mon Sep 17 00:00:00 2001 +From: Zhipeng Xie +Date: Thu, 14 Feb 2019 14:21:20 +0000 +Subject: [PATCH] kpatch-build: adapt for native compile_env + +we check vmlinux to determine if klp_func and klp_object +have some members and set flag for livepatch-patch-hook.c. +support arm64 native compile enviroment. + +Signed-off-by: Zhipeng Xie +--- + kpatch-build/kpatch-build | 46 ++++++++++++++++++++++++++++++++++---------- + 1 files changed, 35 insertions(+), 11 deletions(-) + +diff --git a/kpatch-build/kpatch-build b/kpatch-build/kpatch-build +index c227b44..18f79d4 100755 +--- a/kpatch-build/kpatch-build ++++ b/kpatch-build/kpatch-build +@@ -279,7 +279,7 @@ find_special_section_data() { + # shellcheck disable=SC2086 + SPECIAL_VARS="$(readelf -wi "$VMLINUX" | + gawk --non-decimal-data $AWK_OPTIONS ' +- BEGIN { a = b = p = e = o = f = 0 } ++ BEGIN { a = b = p = e = o = c = f = s = i = r = j = h = 0 } + + # Set state if name matches + a == 0 && /DW_AT_name.* alt_instr[[:space:]]*$/ {a = 1; next} +@@ -287,7 +287,8 @@ find_special_section_data() { + p == 0 && /DW_AT_name.* paravirt_patch_site[[:space:]]*$/ {p = 1; next} + e == 0 && /DW_AT_name.* exception_table_entry[[:space:]]*$/ {e = 1; next} + o == 0 && /DW_AT_name.* orc_entry[[:space:]]*$/ {o = 1; next} +- f == 0 && /DW_AT_name.* klp_func[[:space:]]*$/ {f = 1; next} ++ c == 0 && /DW_AT_name.* klp_func[[:space:]]*$/ {c = 1; next} ++ j == 0 && /DW_AT_name.* klp_object[[:space:]]*$/ {j = 1; next} + + # Reset state unless this abbrev describes the struct size + a == 1 && !/DW_AT_byte_size/ { a = 0; next } +@@ -295,8 +296,13 @@ find_special_section_data() { + p == 1 && !/DW_AT_byte_size/ { p = 0; next } + e == 1 && !/DW_AT_byte_size/ { e = 0; next } + o == 1 && !/DW_AT_byte_size/ { o = 0; next } +- f == 1 && /DW_TAG_structure_type/ { f = 3; next } +- f == 1 && /DW_AT_name.* force[[:space:]]*$/ {f = 2; next} ++ c == 1 && /DW_TAG_structure_type/ { c = 3; next } ++ j == 1 && /DW_TAG_structure_type/ { j = 3; next } ++ c == 1 && /DW_AT_name.* force[[:space:]]*$/ {f = 2; next} ++ c == 1 && /DW_AT_name.* old_sympos[[:space:]]*$/ {s = 2; next} ++ i == 1 && /DW_AT_name.* immediate[[:space:]]*$/ {i = 2; next} ++ j == 1 && /DW_AT_name.* relocs[[:space:]]*$/ {r = 2; next} ++ j == 1 && /DW_AT_name.* hooks_load[[:space:]]*$/ {h = 2; next} + + # Now that we know the size, stop parsing for it + a == 1 {printf("export ALT_STRUCT_SIZE=%d\n", $4); a = 2} +@@ -304,10 +310,14 @@ find_special_section_data() { + p == 1 {printf("export PARA_STRUCT_SIZE=%d\n", $4); p = 2} + e == 1 {printf("export EX_STRUCT_SIZE=%d\n", $4); e = 2} + o == 1 {printf("export ORC_STRUCT_SIZE=%d\n", $4); o = 2} +- f == 2 {printf("export KLP_SUPPORT_FORCE=y\n"); f = 3} ++ f == 2 {printf("export KLP_SUPPORT_FORCE=y\n"); f = 3} ++ s == 2 {printf("export KLP_SUPPORT_OLD_SYMPOS=y\n"); s = 3} ++ i == 2 {printf("export KLP_SUPPORT_IMMEDIATE=y\n"); i = 3} ++ r == 2 {printf("export KLP_SUPPORT_RELOCS=y\n"); r = 3} ++ h == 2 {printf("export KLP_SUPPORT_LOADHOOKS=y\n"); h = 3} + + # Bail out once we have everything +- a == 2 && b == 2 && (p == 2 || skip_p) && e == 2 && (o == 2 || skip_o) && f == 3 {exit}')" ++ a == 2 && b == 2 && (p == 2 || skip_p) && e == 2 && (o == 2 || skip_o) && c == 3 && j == 3 {exit}')" + + [[ -n "$SPECIAL_VARS" ]] && eval "$SPECIAL_VARS" + +@@ -406,7 +416,9 @@ arch_export() { + export GCC_ADD_OPTION= + elif [[ $E_MACHINE -eq 183 ]]; then + export ARCH=arm64 +- export ARCH_COMPILE=aarch64-linux-gnu- ++ if [ $(arch) != "aarch64" ]; then ++ export ARCH_COMPILE=aarch64-linux-gnu- ++ fi + export ENDIAN=little + if grep "\-mlong-calls" $SRCDIR/Makefile > /dev/null; then + export GCC_ADD_OPTION="-fno-section-anchors -mlong-calls" +@@ -953,10 +965,6 @@ if "$KPATCH_MODULE"; then + export KCPPFLAGS="-D__KPATCH_MODULE__" + fi + +-if grep "hulk" $SRCDIR/Makefile > /dev/null; then +- export KCPPFLAGS="-D__HULK__ $KCPPFLAGS" +-fi +- + if [[ -n "$NO_STACK_CHECK" ]];then + export KCPPFLAGS="-D__ALL_FORCE__ $KCPPFLAGS" + fi +@@ -965,6 +973,22 @@ if [[ -n "$KLP_SUPPORT_FORCE" ]];then + export KCPPFLAGS="-D__KLP_SUPPORT_FORCE__ $KCPPFLAGS" + fi + ++if [[ -n "$KLP_SUPPORT_OLD_SYMPOS" ]];then ++ export KCPPFLAGS="-DHAVE_SYMPOS $KCPPFLAGS" ++fi ++ ++if [[ -n "$KLP_SUPPORT_IMMEDIATE" ]];then ++ export KCPPFLAGS="-DHAVE_IMMEDIATE $KCPPFLAGS" ++fi ++ ++if [[ -n "$KLP_SUPPORT_RELOCS" ]];then ++ export KCPPFLAGS="-DHAVE_ELF_RELOCS $KCPPFLAGS" ++fi ++ ++if [[ -n "$KLP_SUPPORT_LOADHOOKS" ]];then ++ export KCPPFLAGS="-DHAVE_LOADHOOKS $KCPPFLAGS" ++fi ++ + echo "Building patch module: $MODNAME.ko" + + if [[ -z "$USERSRCDIR" ]] && [[ "$DISTRO" = ubuntu ]]; then +-- +1.7.5.4 + diff --git a/9026-add-find_special_section_data_arm64-for-arm64.patch b/9026-add-find_special_section_data_arm64-for-arm64.patch new file mode 100644 index 0000000..283cdca --- /dev/null +++ b/9026-add-find_special_section_data_arm64-for-arm64.patch @@ -0,0 +1,96 @@ +From d53b2d1f87f5e891ba8f6945765134da9ee2d29d Mon Sep 17 00:00:00 2001 +From: Zhipeng Xie +Date: Thu, 7 Mar 2019 14:38:15 +0000 +Subject: [PATCH] add find_special_section_data_arm64 for arm64 + +arm64 kernel have no paravirt_patch_site or orc_entry structure +in vmlinux, we don't need to check these two struct for arm64. + +Signed-off-by: Zhipeng Xie +--- + kpatch-build/kpatch-build | 56 ++++++++++++++++++++++++++++++++++++++- + 1 file changed, 55 insertions(+), 1 deletion(-) + +diff --git a/kpatch-build/kpatch-build b/kpatch-build/kpatch-build +index 18f79d4..59af250 100755 +--- a/kpatch-build/kpatch-build ++++ b/kpatch-build/kpatch-build +@@ -266,12 +266,66 @@ find_special_section_data_ppc64le() { + return + } + ++find_special_section_data_arm64() { ++ ++ # If $AWK_OPTIONS are blank gawk would treat "" as a blank script ++ # shellcheck disable=SC2086 ++ SPECIAL_VARS="$(readelf -wi "$VMLINUX" | ++ gawk --non-decimal-data $AWK_OPTIONS ' ++ BEGIN { a = b = e = c = f = s = i = r = j = h = 0 } ++ ++ # Set state if name matches ++ a == 0 && /DW_AT_name.* alt_instr[[:space:]]*$/ {a = 1; next} ++ b == 0 && /DW_AT_name.* bug_entry[[:space:]]*$/ {b = 1; next} ++ e == 0 && /DW_AT_name.* exception_table_entry[[:space:]]*$/ {e = 1; next} ++ c == 0 && /DW_AT_name.* klp_func[[:space:]]*$/ {c = 1; next} ++ j == 0 && /DW_AT_name.* klp_object[[:space:]]*$/ {j = 1; next} ++ ++ # Reset state unless this abbrev describes the struct size ++ a == 1 && !/DW_AT_byte_size/ { a = 0; next } ++ b == 1 && !/DW_AT_byte_size/ { b = 0; next } ++ e == 1 && !/DW_AT_byte_size/ { e = 0; next } ++ c == 1 && /DW_TAG_structure_type/ { c = 3; next } ++ j == 1 && /DW_TAG_structure_type/ { j = 3; next } ++ c == 1 && /DW_AT_name.* force[[:space:]]*$/ {f = 2; next} ++ c == 1 && /DW_AT_name.* old_sympos[[:space:]]*$/ {s = 2; next} ++ i == 1 && /DW_AT_name.* immediate[[:space:]]*$/ {i = 2; next} ++ j == 1 && /DW_AT_name.* relocs[[:space:]]*$/ {r = 2; next} ++ j == 1 && /DW_AT_name.* hooks_load[[:space:]]*$/ {h = 2; next} ++ ++ # Now that we know the size, stop parsing for it ++ a == 1 {printf("export ALT_STRUCT_SIZE=%d\n", $4); a = 2} ++ b == 1 {printf("export BUG_STRUCT_SIZE=%d\n", $4); b = 2} ++ e == 1 {printf("export EX_STRUCT_SIZE=%d\n", $4); e = 2} ++ f == 2 {printf("export KLP_SUPPORT_FORCE=y\n"); f = 3} ++ s == 2 {printf("export KLP_SUPPORT_OLD_SYMPOS=y\n"); s = 3} ++ i == 2 {printf("export KLP_SUPPORT_IMMEDIATE=y\n"); i = 3} ++ r == 2 {printf("export KLP_SUPPORT_RELOCS=y\n"); r = 3} ++ h == 2 {printf("export KLP_SUPPORT_LOADHOOKS=y\n"); h = 3} ++ ++ # Bail out once we have everything ++ a == 2 && b == 2 && e == 2 && c == 3 && j == 3 {exit}')" ++ ++ [[ -n "$SPECIAL_VARS" ]] && eval "$SPECIAL_VARS" ++ ++ [[ -z "$ALT_STRUCT_SIZE" ]] && die "can't find special struct alt_instr size" ++ [[ -z "$BUG_STRUCT_SIZE" ]] && die "can't find special struct bug_entry size" ++ [[ -z "$EX_STRUCT_SIZE" ]] && die "can't find special struct exception_table_entry size" ++ ++ return ++} ++ + find_special_section_data() { + if [[ "$ARCH" = "ppc64le" ]]; then + find_special_section_data_ppc64le + return + fi + ++ if [[ "$ARCH" = "arm64" ]]; then ++ find_special_section_data_arm64 ++ return ++ fi ++ + [[ "$CONFIG_PARAVIRT" -eq 0 ]] && AWK_OPTIONS="-vskip_p=1" + [[ "$CONFIG_UNWINDER_ORC" -eq 0 ]] && AWK_OPTIONS="$AWK_OPTIONS -vskip_o=1" + +@@ -323,7 +377,7 @@ find_special_section_data() { + + [[ -z "$ALT_STRUCT_SIZE" ]] && die "can't find special struct alt_instr size" + [[ -z "$BUG_STRUCT_SIZE" ]] && die "can't find special struct bug_entry size" +- [[ -z "$EX_STRUCT_SIZE" ]] && die "can't find special struct paravirt_patch_site size" ++ [[ -z "$EX_STRUCT_SIZE" ]] && die "can't find special struct exception_table_entry size" + [[ -z "$PARA_STRUCT_SIZE" && "$CONFIG_PARAVIRT" -ne 0 ]] && die "can't find special struct paravirt_patch_site size" + [[ -z "$ORC_STRUCT_SIZE" && "$CONFIG_UNWINDER_ORC" -ne 0 ]] && die "can't find special struct orc_entry size" + +-- +2.19.1 + diff --git a/9027-fix-ref-static-local-symbol-for-longname-symbol.patch b/9027-fix-ref-static-local-symbol-for-longname-symbol.patch new file mode 100644 index 0000000..88be441 --- /dev/null +++ b/9027-fix-ref-static-local-symbol-for-longname-symbol.patch @@ -0,0 +1,31 @@ +From 1069d212fd848f1f1e2425dffe8e9aea188c6150 Mon Sep 17 00:00:00 2001 +From: Zhipeng Xie +Date: Tue, 21 Dec 2083 12:18:38 +0800 +Subject: [PATCH] fix ref static local symbol for longname symbol + +static local symbol have a "." which will confuse +the kernel livepatch klp_resolve_symbols. So, pass +static local symbols in lookup_ref_symbol_offset. + +Signed-off-by: Zhipeng Xie +--- + kpatch-build/lookup.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/kpatch-build/lookup.c b/kpatch-build/lookup.c +index 2e55862..01abc41 100644 +--- a/kpatch-build/lookup.c ++++ b/kpatch-build/lookup.c +@@ -591,7 +591,8 @@ int lookup_ref_symbol_offset(struct lookup_table *table, char *name, + /*find a unique symbol in the same section first*/ + for_each_obj_symbol(i, sym, table) { + if (!strcmp(sym->name, name) || sym->type == STT_FILE || +- sym->sec_index != orig_sym->sec_index) ++ sym->sec_index != orig_sym->sec_index || ++ strchr(sym->name, '.')) + continue; + + if (!lookup_is_duplicate_symbol(table, sym->name, objname, 1)) { +-- +2.19.1 + diff --git a/9028-add-object-in-kpatch.patch b/9028-add-object-in-kpatch.patch new file mode 100644 index 0000000..b103ed6 --- /dev/null +++ b/9028-add-object-in-kpatch.patch @@ -0,0 +1,33 @@ +From d6304fcd36edd4e9df48687517f30965d9a790e9 Mon Sep 17 00:00:00 2001 +From: Bin Yang +Date: Tue, 16 Jul 2019 14:39:27 +0800 +Subject: [PATCH] add object in kpatch + +--- + kpatch-build/kpatch-build | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/kpatch-build/kpatch-build b/kpatch-build/kpatch-build +index 59af250..f685654 100644 +--- a/kpatch-build/kpatch-build ++++ b/kpatch-build/kpatch-build +@@ -1011,6 +1011,8 @@ echo -n "Patched objects:" + for i in $(echo "${objnames[@]}" | tr ' ' '\n' | sort -u | tr '\n' ' ') + do + echo -n " $i" ++ echo -n " $(basename $i)" ++ echo -n "$(basename $i)" >> $TEMPDIR/patch/object + done + echo + +@@ -1113,6 +1115,7 @@ UNDEFINED=$(comm -23 <(sort -u "${TEMPDIR}"/undefined_references) \ + [[ -z "$USERMODDIR" ]] && [[ ! -z "$UNDEFINED" ]] && die "Undefined symbols: $UNDEFINED" + + cp -f "$TEMPDIR/patch/$MODNAME.ko" "$BASE" || die ++cp -f "$TEMPDIR/patch/object" "$BASE" || die + + [[ "$DEBUG" -eq 0 ]] && rm -f "$LOGFILE" + +-- +2.17.1 + diff --git a/9030-kmod-core-fix-compilation-with-CONFIG_HAVE_ARCH_PREL.patch b/9030-kmod-core-fix-compilation-with-CONFIG_HAVE_ARCH_PREL.patch new file mode 100644 index 0000000..58c2278 --- /dev/null +++ b/9030-kmod-core-fix-compilation-with-CONFIG_HAVE_ARCH_PREL.patch @@ -0,0 +1,34 @@ +From da3eed612df1d26e19b0678763e116f666da13b2 Mon Sep 17 00:00:00 2001 +From: Artem Savkov +Date: Wed, 14 Nov 2018 12:33:13 +0100 +Subject: [PATCH] kmod/core: fix compilation with + CONFIG_HAVE_ARCH_PREL32_RELOCATIONS + +Kernel commit 7290d5809571 "module: use relative references for +__ksymtab entries" changed kernel_symbol structure on some +architectures. Adjust kmod/core/core.c accordingly. + +Signed-off-by: Artem Savkov +--- + kmod/core/core.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/kmod/core/core.c b/kmod/core/core.c +index 4a73a47..a91d417 100644 +--- a/kmod/core/core.c ++++ b/kmod/core/core.c +@@ -651,7 +651,11 @@ static int kpatch_find_external_symbol(const char *objname, const char *name, + sym = find_symbol(name, NULL, NULL, true, true); + preempt_enable(); + if (sym) { ++#ifdef CONFIG_HAVE_ARCH_PREL32_RELOCATIONS ++ *addr = (unsigned long)offset_to_ptr(&sym->value_offset); ++#else + *addr = sym->value; ++#endif + return 0; + } + +-- +2.19.1 + diff --git a/README.md b/README.md deleted file mode 100644 index ff3252a..0000000 --- a/README.md +++ /dev/null @@ -1,39 +0,0 @@ -# kpatch - -#### 浠嬬粛 -{**浠ヤ笅鏄爜浜戝钩鍙拌鏄庯紝鎮ㄥ彲浠ユ浛鎹㈡绠浠** -鐮佷簯鏄 OSCHINA 鎺ㄥ嚭鐨勫熀浜 Git 鐨勪唬鐮佹墭绠″钩鍙帮紙鍚屾椂鏀寔 SVN锛夈備笓涓哄紑鍙戣呮彁渚涚ǔ瀹氥侀珮鏁堛佸畨鍏ㄧ殑浜戠杞欢寮鍙戝崗浣滃钩鍙 -鏃犺鏄釜浜恒佸洟闃熴佹垨鏄紒涓氾紝閮借兘澶熺敤鐮佷簯瀹炵幇浠g爜鎵樼銆侀」鐩鐞嗐佸崗浣滃紑鍙戙備紒涓氶」鐩鐪 [https://gitee.com/enterprises](https://gitee.com/enterprises)} - -#### 杞欢鏋舵瀯 -杞欢鏋舵瀯璇存槑 - - -#### 瀹夎鏁欑▼ - -1. xxxx -2. xxxx -3. xxxx - -#### 浣跨敤璇存槑 - -1. xxxx -2. xxxx -3. xxxx - -#### 鍙備笌璐$尞 - -1. Fork 鏈粨搴 -2. 鏂板缓 Feat_xxx 鍒嗘敮 -3. 鎻愪氦浠g爜 -4. 鏂板缓 Pull Request - - -#### 鐮佷簯鐗规妧 - -1. 浣跨敤 Readme\_XXX.md 鏉ユ敮鎸佷笉鍚岀殑璇█锛屼緥濡 Readme\_en.md, Readme\_zh.md -2. 鐮佷簯瀹樻柟鍗氬 [blog.gitee.com](https://blog.gitee.com) -3. 浣犲彲浠 [https://gitee.com/explore](https://gitee.com/explore) 杩欎釜鍦板潃鏉ヤ簡瑙g爜浜戜笂鐨勪紭绉寮婧愰」鐩 -4. [GVP](https://gitee.com/gvp) 鍏ㄧО鏄爜浜戞渶鏈変环鍊煎紑婧愰」鐩紝鏄爜浜戠患鍚堣瘎瀹氬嚭鐨勪紭绉寮婧愰」鐩 -5. 鐮佷簯瀹樻柟鎻愪緵鐨勪娇鐢ㄦ墜鍐 [https://gitee.com/help](https://gitee.com/help) -6. 鐮佷簯灏侀潰浜虹墿鏄竴妗g敤鏉ュ睍绀虹爜浜戜細鍛橀閲囩殑鏍忕洰 [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/) diff --git a/kpatch-0.6.1.tar.gz b/kpatch-0.6.1.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..1be0f4a14e1005da8570ce9ceec88eb43f99ea40 GIT binary patch literal 147195 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�J2~Gw3r_d{zvjG!4>}s!u}GPM;(0XU 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 z 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 Y8q$!4G^8O7X;@$QFZ3jc#{kF*0LXO{8UO$Q literal 0 HcmV?d00001 diff --git a/kpatch.spec b/kpatch.spec new file mode 100644 index 0000000..39d4070 --- /dev/null +++ b/kpatch.spec @@ -0,0 +1,249 @@ +%global raw_version 0.6.1 + +Name: kpatch +Version: 2.0 +Release: 3.1.22 +Summary: A Linux dynamic kernel patching infrastructure + +License: GPLv2 +URL: https://github.com/dynup/kpatch +Source0: https://github.com/dynup/kpatch/archive/%{name}-%{raw_version}.tar.gz + +Source1: os_hotpatch +Source2: livepatch +Source3: make_hotpatch + +Patch9001: 9001-livepatch-patch-hook-don-t-active-patch-when-insmod.patch +Patch9002: 9002-kpatch-build-support-third-party-module-make-hotpatc.patch +Patch9003: 9003-kpatch-build-support-makefile-not-in-third-party-mod.patch +Patch9004: 9004-create-diff-object-new-static-var-should-be-included.patch +Patch9005: 9005-livepatch-fix-use-THIS-modname-as-the-name-of-ddebug.patch +Patch9006: 9006-create-diff-object-fix-correlate-static-local-variab.patch +Patch9007: 9007-create-diff-object-don-t-create-dynamic-reloc-for-sy.patch +Patch9008: 9008-livepatch-patch-hook-support-force-enable-disable-fu.patch +Patch9009: 9009-kmod-kpatch-build-support-build-patch-for-old-kernel.patch +Patch9010: 9010-kmod-kpatch-build-support-cross-compile-hotpatch-for.patch +Patch9011: 9011-kpatch-build-use-.klp.rela-in-euleros-7.5-kernel.patch +Patch9012: 9012-create-diff-object-create-dynamic-relocs-for-changed.patch +Patch9013: 9013-kmod-kpatch-build-fix-duplicate-symbol-relocation-fo.patch +Patch9014: 9014-create-diff-object-add-dynamic-reloction-for-functio.patch +Patch9015: 9015-create-diff-object-exclude-line-only-change-for-arm6.patch +Patch9016: 9016-kpatch-build-include-secsym-in-kpatch_mark_ignored_s.patch +Patch9017: 9017-support-compile-kpatch-on-aarch64.patch +Patch9018: 9018-support-c-plus-kernel-module.patch +Patch9019: 9019-fix-rodata.str-problem.patch +Patch9020: 0001-Add-__addressable_-to-maybe_discarded_sym.patch +Patch9021: 0002-kmod-patch-fix-patch-linking-with-4.20.patch +Patch9022: 0003-kmod-patch-more-linking-fixes.patch +Patch9023: 9023-kpatch-build-adapt-for-ksymtab-in-4.19-kernel.patch +Patch9024: 9024-support-force-enable-disable-for-kernel-4.19.patch +Patch9025: 9025-kpatch-build-adapt-for-native-compile_env.patch +Patch9026: 9026-add-find_special_section_data_arm64-for-arm64.patch +Patch9027: 9027-fix-ref-static-local-symbol-for-longname-symbol.patch +Patch9028: 9028-add-object-in-kpatch.patch +Patch9029: 0004-create-diff-object-allow-changing-subsections.patch +Patch9030: 9030-kmod-core-fix-compilation-with-CONFIG_HAVE_ARCH_PREL.patch + +BuildRequires: gcc elfutils-libelf-devel uname-build-checks kernel kernel-devel +Requires: bc tar bash kmod + +Provides: kpatch-runtime +Obsoletes: kpatch-runtime + +%description +kpatch is a Linux dynamic kernel patching infrastructure which allows you to patch +a running kernel without rebooting or restarting any processes. It enables sysadmins +to apply critical security patches to the kernel immediately, without having to wait +for long-running tasks to complete, for users to log off, or for scheduled reboot +windows. It gives more control over uptime without sacrificing security or stability. + +%package_help + +%prep +%autosetup -n %{name}-%{raw_version} -p1 + +%build +export CFLAGS="$RPM_OPT_FLAGS" LDFLAGS="$RPM_LD_FLAGS" +%make_build + +%install +%make_install PREFIX=%{_prefix} + +install -Dm 0750 -t %{buildroot}/%{_bindir} %{SOURCE1} %{SOURCE2} +install -Dm 0500 -t %{buildroot}/opt/patch_workspace/ %{SOURCE3} +pushd %{buildroot}/opt/patch_workspace +mkdir hotpatch package +popd + +%files +%defattr(-,root,root) +%doc COPYING README.md +%{_bindir}/* +%{_prefix}/lib/systemd/system/* +%{_libexecdir}/kpatch +%{_prefix}/sbin/kpatch +%{_datadir}/%{name}/* +%{_sysconfdir}/init/* +%{_bindir}/livepatch +%{_bindir}/os_hotpatch +/opt/patch_workspace/* +%ifarch x86_64 +%{_prefix}/lib/kpatch +%endif + +%files help +%{_mandir}/man1/*.1.gz + +%changelog +* Mon Dec 30 2019 openEuler Buildteam -2.0-3.1.22 +- Type:enhancement +- ID:NA +- SUG:NA +- DESC:change some patch name and delete useless code + +* Mon Dec 23 2019 openEuler Buildteam -2.0-3.1.21 +- Type:enhancement +- ID:NA +- SUG:NA +- DESC:modify email adress + +* Thu Dec 19 2019 chengquan -2.0-3.1.20 +- Type:enhancement +- ID:NA +- SUG:NA +- DESC:remove useless description + +* Thu Nov 28 2019 Yufa Fang - 2.0-3.1.19 +- Type:bugfix +- ID:NA +- SUG:restart +- DESC:fix compilation with CONFIG_HAVE_ARCH_PREL32_RELOCATIONS + +* Thu Oct 10 2019 Zhipeng Xie - 2.0-3.1.18 +- Type:enhancement +- ID:NA +- SUG:restart +- DESC:add security compile flags + +* Tue Sep 27 2019 Zhipeng Xie - 2.0-3.1.17 +- Type:enhancement +- ID:NA +- SUG:restart +- DESC:create-diff-object: allow changing subsections + +* Tue Sep 24 2019 shenyangyang -2.0-3.1.16 +- Type:enhancement +- ID:NA +- SUG:NA +- DESC:revise help package and subpackage + +* Mon Aug 26 2019 openEuler Buildteam -2.0-3.1.15 +- Type:enhancement +- ID:NA +- SUG:NA +- DESC:changelog some patch commit message + +* Tue Aug 20 2019 openEuler Builteam -2.0-3.1.14 +- Type:NA +- ID:NA +- SUG:NA +- DESC:rewrite spec + +* Fri Jul 16 2019 yangbin - 2.0-3.1.13 +- Type:enhancement +- ID:NA +- SUG:restart +- DESC:add object in kpatch + +* Fri Jul 5 2019 Zhipeng Xie - 2.0-3.1.12 +- Type:bugfix +- ID:NA +- SUG:restart +- DESC:fix ref static local symbol for longname symbol + +* Mon Jul 1 2019 Enbo Kang - 2.0-3.1.11 +- Type:enhancement +- ID:NA +- SUG:restart +- DESC:fix security problem + +* Tue May 7 2019 Zhipeng Xie - 2.0-3.1.10 +- Type:enhancement +- ID:NA +- SUG:restart +- DESC:change some patch to backport prefix + +* Sat Apr 13 2019 hezhanyu - 2.0-3.1.9 +- Type:enhancement +- ID:NA +- SUG:restart +- DESC:modify private key in sign-modules + +* Thu Apr 4 2019 Enbo Kang - 2.0-3.1.8 +- Type:enhancement +- ID:NA +- SUG:restart +- DESC:delete sensitive information + +* Thu Mar 28 2019 Enbo Kang - 2.0-3.1.7 +- Type:enhancement +- ID:NA +- SUG:restart +- DESC:add RELRO and PIE for create-kpatch-module, create-diff-object, create-klp-module + +* Sat Mar 23 2019 Zhipeng Xie - 2.0-3.1.6 +- Type:enhancement +- ID:NA +- SUG:restart +- DESC:upgrade to upstream version 0.6.1 + +* Thu Mar 7 2019 Zhipeng Xie - 2.0-3.1.5 +- Type:bugfix +- ID:NA +- SUG:restart +- DESC:add find_special_section_data_arm64 for arm64 + +* Tue Feb 26 2019 Zhipeng Xie - 2.0-3.1.4 +- Type:enhancement +- ID:NA +- SUG:restart +- DESC:add packages required by kpatch and kpatch-runtime + +* Mon Feb 25 2019 Zhipeng Xie - 2.0-3.1.3 +- Type:enhancement +- ID:NA +- SUG:restart +- DESC:adapt for native compile_env + +* Mon Feb 11 2019 Zhipeng Xie - 2.0-3.1.2 +- Type:enhancement +- ID:NA +- SUG:restart +- DESC:support kernel-4.19 + +* Thu Dec 20 2018 Zhipeng Xie - 2.0-3.1.1 +- Type:enhancement +- ID:NA +- SUG:restart +- DESC:support c++ kernel module + +* Wed Dec 19 2018 Zhipeng Xie - 2.0-3.1.0 +- Type:enhancement +- ID:NA +- SUG:restart +- DESC:support compile kpatch on aarch64 + +* Fri Nov 23 2018 Zhipeng Xie - 2.0-2.7.2 +- Type:enhancement +- ID:NA +- SUG:restart +- DESC:fix some kpatch-build fail cases + +* Sat Nov 3 2018 Zhipeng Xie - 2.0-2.7.1 +- Type:enhancement +- ID:NA +- SUG:restart +- DESC:rebase kpatch + +* Thu Nov 16 2017 openEuler Builteam 0.4.0-3 +- Package init diff --git a/livepatch b/livepatch new file mode 100644 index 0000000..e6e1093 --- /dev/null +++ b/livepatch @@ -0,0 +1,65 @@ +#!/bin/bash +# Copyright (C) 2019. Huawei Technologies Co., Ltd. All rights reserved. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 and +# only version 2 as published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +exe_tool=`which os_hotpatch` +fn_help() +{ +cat < + -q[patch]/--query[=patch] + -h/--help -v/--version +e.g. : livepatch --load +EOFE +} +if [ "$1" = "-q" -o "$1" = "--query" ];then + $exe_tool -q all + exit 0 +fi +input_args=`getopt -a -o l:a:r:d:q:v -l load:,activate:,remove:,deactivate:,query:,help,version -- "$@" 2>&1` +eval set -- "${input_args}" +while true; +do + case "$1" in + -l|--load) + $exe_tool -l "$2" + exit $? + ;; + -a|--activate) + $exe_tool -a "klp_${2#klp_}" + exit $? + ;; + -d|--deactivate) + $exe_tool -r "klp_${2#klp_}" + exit $? + ;; + -r|--remove) + $exe_tool -d "klp_${2#klp_}" + exit $? + ;; + -q|--query) + $exe_tool -q "klp_${2#klp_}" + exit $? + ;; + -h|--help) + fn_help + exit 0 + ;; + -v|--version) + echo "LKP:livepatch version 2.0-00000" + exit 0 + ;; + *) + fn_help + exit 1 + ;; + esac +done diff --git a/make_hotpatch b/make_hotpatch new file mode 100644 index 0000000..3057146 --- /dev/null +++ b/make_hotpatch @@ -0,0 +1,726 @@ +#!/bin/bash +# Copyright (C) 2019. Huawei Technologies Co., Ltd. All rights reserved. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 and +# only version 2 as published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +SHELL_DIR=$(dirname $0) +SHELL_DIR=$(cd $SHELL_DIR; pwd) +G_PRIVATE_MODULE= +G_HOTPATCH= +G_HOTPATCH_ID= +G_HOTPATCH_TAR= +G_DIFFEXT= +G_JOBS="$(getconf _NPROCESSORS_ONLN)" +G_PATCH_SRC= +G_KERNEL_SRC=/opt/patch_workspace/kernel-source +G_KERNEL_CONFIG=/opt/patch_workspace/.config +G_HOTPATCH_DIR=/opt/patch_workspace/hotpatch +G_VMLINUX=/opt/patch_workspace/vmlinux +G_PREFIX=klp +G_TMP_DIR= +G_PATCHFILE= +G_MODULE_SRC= +G_MODULE_MAKEFILE= +G_KPLICE_PWD_FIELD="KPLICE_PWD" +G_PRIVATE_MODULE_SRC_FIELD="PRIVATE_MODULE_SRC" +G_KPATCH_FLAGS=/opt/patch_workspace/.flags +G_DEBUG_INFO= +G_EXT_FLAGS= +USERMODBUILDDIR= + +######################################################### +# Description: usage +# Input: +# Return: 0-success +######################################################### +function fn_usage() +{ + cat << EOF +Usage: + make_hotpatch [*OPTIONS*] -d patch_diffext -i patch_id -m module_src + +Options: + -d,--diffext + make hotpatch using the modified source files with + names ending in *patch_diffext*. The patch will be determined by + comparing all of the files in the build directory tree + whose names end with the extra extension *patch_diffext* against the + corresponding files without the extra extension. + -j,--jobs + Specifies the number of jobs to run simultaneously while + performing builds. + -i,--id + Specifies the unique value that will be used as the identifier + of the hotpatch. + -m,--modulesrc + Specifies the module src path for make user module hotpatch. + -f,--makefile + Specifies the module makefile for make user module hotpatch. + --extra_flags + Specifies extra flags file for make user module hotpatch. + --no_stack_check + make hotpatch without stack check when activating or deactivating this patch. + --debug_info + Save debug info when hotpatch building.Default is closed. + -p,--patch + Specifies the patch file + --kallsyms + Specifies module kallsyms in running system(cat /proc/kallsyms|grep mod) + -h,--help + help info +EOF + + return 0 +} + + +######################################################### +# Description: fn_do_clean, remove tmp file +# Input: +# $1: init flag +# Return: 0-success +######################################################### +function fn_do_clean() +{ + local ret=0 + G_EXT_FLAGS= + unset NO_STACK_CHECK + unset KALLSYMS + rm -rf $G_TMP_DIR + +} + +######################################################### +# Description: fn_check_reg_char +# Input: +# $@: input param +# Return: 0-success,1-failed +######################################################### +function fn_check_reg_char() +{ + local l_str=$1 + local l_str_maxlen=$2 + local l_str_ex=$3 + local len_str=${#l_str} + + if [ -z "$l_str" ];then + echo "error: the string is empty, check string failed" + return 1 + fi + ##字符串长度 + if [ -n "$l_str_maxlen" ] && [ -z "`echo $l_str_maxlen | sed 's/[0-9]//g'`" ];then + if [ $len_str -gt $l_str_maxlen ]; then + echo "error: The length of $l_str exceed max length $l_str_maxlen." + return 1 + fi + fi + #不能包含其他字符 + if [ -n "$l_str_ex" ] && [ -n "`echo $l_str | grep -E [$l_str_ex] 2>/dev/null`" ];then + echo "error: string $l_str included characters $l_str_ex." + return 1 + fi + ##数字和字母开头 + if [ -z "`echo $l_str | grep -E '^[a-z0-9A-Z]'`" ];then + echo "error: string $l_str must start with a character ('0-9' or 'A-Z' or 'a-z')." + return 1 + fi + ##只能数字和字母 -_ + if [ -n "`echo $l_str | grep -E '[^a-z0-9A-Z_-]'`" ];then + if [ -n "$l_str_ex" ] ;then + ##这个日志写不好 + echo "error: string $l_str can only contain characters included by ('0-9', 'a-z', 'A-Z')" + else + echo "error: string $l_str can only contain characters included by ('0-9', 'a-z', 'A-Z', '-', '_')." + fi + + return 1 + fi + +} + +######################################################### +# Description: fn_check_id +# Input: +# $1: +# Return: 0-success,1-failed +######################################################### +function fn_check_id() +{ + local l_id=$1 + fn_check_reg_char "$l_id" "20" "-_" + if [ $? -ne 0 ];then + echo "error: check hotpatch id failed" + return 1 + fi + + G_HOTPATCH_ID=$l_id + G_HOTPATCH=${G_PREFIX}_${G_HOTPATCH_ID}.ko + G_HOTPATCH_TAR=${G_PREFIX}_${G_HOTPATCH_ID}.tar.gz + if [ -f "$G_HOTPATCH_DIR/$G_HOTPATCH_TAR" ];then + echo "error: $G_HOTPATCH_DIR/$G_HOTPATCH_TAR is exist, check hotpatch id failed" + return 1 + fi + return 0 +} + + +######################################################### +# Description: fn_check_jobs +# Input: +# $1: +# Return: 0-success,1-failed +######################################################### +function fn_check_jobs() +{ + local l_jobs=$1 + if [ -z "`echo "$l_jobs" | grep ^[1-9]`" ] || [ -n "`echo "$l_jobs" | sed 's/[0-9]//g'`" ];then + echo "error: the '-j' option requires a positive integral argument" + return 1 + fi + G_JOBS=$l_jobs + return 0 +} + +######################################################### +# Description: fn_check_patch +# Input: +# $1: +# Return: 0-success,1-failed +######################################################### +function fn_check_patch(){ + local l_patch=$1 + if [ ! -f $1 ];then + echo "error:patch file $1 not exit" + return 1 + fi + G_PATCHFILE=$l_patch +} +######################################################### +# Description: fn_check_diffext +# Input: +# $1: +# Return: 0-success,1-failed +######################################################### +function fn_check_diffext() +{ + local l_diffext=$1 + + if [ -z "$l_diffext" ];then + echo "error: diffext is empty, check diffext failed" + return 1 + fi + G_DIFFEXT=$l_diffext + return 0 +} + + +######################################################### +# Description: fn_check_kernelsrc +# Input: +# $1: +# Return: 0-success,1-failed +######################################################### +function fn_check_kernelsrc() +{ + local l_kernelsrc=$1 + + if [ ! -d "$l_kernelsrc" ];then + echo "error: kernel src $l_kernelsrc is not exist, check kernel src failed" + return 1 + fi + G_KERNEL_SRC=$l_kernelsrc + return 0 +} + +######################################################### +# Description: fn_check_modulesrc +# Input: +# $1: +# Return: 0-success,1-failed +######################################################### +function fn_check_modulesrc() +{ + local l_modulesrc=$1 + + if [ ! -d "$l_modulesrc" ];then + echo "error: module src $l_modulesrc is not exist, check module src failed" + return 1 + fi + echo "$l_modulesrc" | grep -q ^/ + if [ $? -ne 0 ];then + echo "error: module src $l_modulesrc must be absolute path, check module src failed" + return 1 + fi + G_MODULE_SRC="$l_modulesrc" + return 0 +} +######################################################### +# Description: fn_check_makefile +# Input: +# $1: +# Return: 0-success,1-failed +######################################################### +function fn_check_makefile() +{ + local l_module_makefile=$1 + + if [ ! -f "$l_module_makefile" ] && [ "$(basename $l_module_makefile)" = "Makefile" ];then + echo "error: module makefile $l_module_makefile is not exist or makefile name is not Makefile, check module makefile failed" + return 1 + fi + echo "$l_module_makefile" | grep -q ^/ + if [ $? -ne 0 ];then + echo "error: module makefile $l_module_makefile must be absolute path, check module src failed" + return 1 + fi + G_MODULE_MAKEFILE=$l_module_makefile + return 0 +} +######################################################### +# Description: fn_check_extra_flags +# Input: +# $1: +# Return: 0-success,1-failed +######################################################### +function fn_check_extra_flags() +{ + local l_extra_flags=$1 + + if [ ! -f "$l_extra_flags" ];then + echo "error: extra flags file $l_extra_flags is not exist, check extra flags failed" + return 1 + fi + G_EXT_FLAGS="`readlink -f ${l_extra_flags}`" + cp -a $l_extra_flags $G_KPATCH_FLAGS + if [ $? -ne 0 ];then + echo "error: copy $l_extra_flags to $G_KPATCH_FLAGS failed" + return 1 + fi + return 0 +} + +######################################################### +# Description: verify input param +# Input: +# $@: input param +# Return: 0-success,1-failed +######################################################### +function fn_verify_input() +{ + local input_param=$@ + + if [ $# -lt 1 ]; then + echo "error: missing param,please check it" + fn_do_clean + fn_usage + exit 1 + fi + + if [ -z "`echo "$input_param" | grep -w "\-i"`" \ + -a -z "`echo $input_param | grep -w "\-\-id"`" \ + -a $# -gt 1 ];then + echo "error: missing param -i or --id" + fn_do_clean + fn_usage + exit 1 + fi + if [ -z "`echo "$input_param" | grep -w "\-d"`" \ + -a -z "`echo $input_param | grep -w "\-\-diffext"`" \ + -a -z "`echo $input_param | grep -w "\-p"`" \ + -a -z "`echo $input_param | grep -w "\-\-patch"`" \ + -a $# -gt 1 ];then + echo "error: missing param -d,--diffext or -p,--patch" + fn_do_clean + fn_usage + exit 1 + fi + + while [ $# -ge 1 ]; do + case "$1" in + -h|--help) + fn_usage + fn_do_clean + exit 0 + ;; + -j|--jobs) + fn_check_jobs $2 + if [ $? -eq 0 ]; then + shift 2 + else + fn_do_clean + fn_usage + exit 1 + fi + ;; + -i|--id) + fn_check_id $2 + if [ $? -eq 0 ]; then + shift 2 + else + fn_do_clean + fn_usage + exit 1 + fi + ;; + -d|--diffext) + fn_check_diffext $2 + if [ $? -eq 0 ]; then + shift 2 + else + fn_do_clean + fn_usage + exit 1 + fi + ;; + -p|--patch) + fn_check_patch $2 + if [ $? -eq 0 ]; then + shift 2 + else + fn_do_clean + fn_usage + exit 1 + fi + ;; + -k|--kernelsrc) + fn_check_kernelsrc $2 + if [ $? -eq 0 ]; then + shift 2 + else + fn_do_clean + fn_usage + exit 1 + fi + ;; + -m|--modulesrc) + fn_check_modulesrc $2 + if [ $? -eq 0 ]; then + shift 2 + else + fn_do_clean + fn_usage + exit 1 + fi + ;; + -f|--makefile) + fn_check_makefile $2 + if [ $? -eq 0 ]; then + shift 2 + else + fn_do_clean + fn_usage + exit 1 + fi + ;; + --extra_flags) + fn_check_extra_flags $2 + if [ $? -eq 0 ]; then + shift 2 + else + fn_do_clean + fn_usage + exit 1 + fi + ;; + --no_stack_check) + export NO_STACK_CHECK="yes" + shift 1 + ;; + --debug_info) + G_DEBUG_INFO="-d" + shift 1 + ;; + --kallsyms) + export KALLSYMS=$(readlink -f $2) + if [ $? -eq 0 ]; then + shift 2 + else + fn_do_clean + fn_usage + exit 1 + fi + ;; + + *) + echo "error: params is invalid,please check it." + fn_do_clean + fn_usage + exit 1 + ;; + esac + done + + + return 0 +} + + +######################################################### +# Description: fn_init_module_build +# Input: +# Return: 0-success,1-failed +######################################################### +function fn_init_module_build() +{ + local l_modulesrc=$1 + local l_module_makefile=$2 + local module= + + module=`basename $l_modulesrc` + + if [ ! -e $G_PRIVATE_MODULE ];then + mkdir -p $G_PRIVATE_MODULE + fi + + rm -rf $G_PRIVATE_MODULE/* + if [ $? -ne 0 ];then + echo "error: remove $G_PRIVATE_MODULE/$module or Makefile failed" + return 1 + fi + + #make a new softlink 或改成链接 + ln -sf $l_modulesrc $G_PRIVATE_MODULE + if [ $? -ne 0 ];then + echo "error: copy $l_modulesrc to $G_PRIVATE_MODULE failed" + return 1 + fi + if [ -z "$l_module_makefile" ];then + l_module_makefile=$l_modulesrc/Makefile + fi + + echo "${G_KPLICE_PWD_FIELD}=${l_modulesrc}/" >> $G_KPATCH_FLAGS + echo "${G_PRIVATE_MODULE_SRC_FIELD}=$(dirname $l_module_makefile)/" >> $G_KPATCH_FLAGS + + fMake=`find ${G_PRIVATE_MODULE}/${module}/ -name Makefile` + #if no Makefile found in module dir + if [ -z "$fMake" ] && [ ! -f "$l_module_makefile" ];then + echo "[ERROR] no Makefilie found in module dir $l_modulesrc" + return 1 + fi + #filter CC in module Makefile + if [ -n "$fMake" ];then + cat $fMake|grep -v '^#'|grep '^[ ,]CC[ ,:,=,?]' + if [ $? -eq 0 ];then + echo "[WARN] ${module}'s Makefile defined CC,please make sure \"CC:=\$(G_KSPLICECC) \$(CC)\" " + fi + fi + if [ -f "$l_module_makefile" ];then + cat $l_module_makefile|grep -v '^#'|grep '^[ ,]CC[ ,:,=,?]' + if [ $? -eq 0 ];then + echo "[WARN] ${module}'s Makefile defined CC,please make sure \"CC:=\$(G_KSPLICECC) \$(CC)\" " + fi + fi +} + + +######################################################### +# Description: fn_makepatch +# Input: +# Return: 0-success,1-failed +######################################################### +function fn_makepatch() +{ + local l_extra_module= + local l_jobs= + local l_ret=0 + local existflag=0 + + G_PATCH_SRC=`readlink -f $G_KERNEL_SRC` + if [ -d "$G_MODULE_SRC" ];then + echo "make out of tree module hotpath" + G_PATCH_SRC=$G_MODULE_SRC + #fn_init_module_build $G_MODULE_SRC $G_MODULE_MAKEFILE + #if [ $? -ne 0 ];then + # echo "error: init module build failed" + # return 1 + #fi + l_extra_module="-m $G_MODULE_SRC" + fi + + if [ -n "$G_JOBS" ];then + l_jobs="--jobs=$G_JOBS" + fi + G_TMP_DIR=/tmp/${G_PREFIX}_${G_HOTPATCH_ID} + mkdir -p $G_TMP_DIR + + if [ -z "$G_PATCHFILE" ];then + #generate src patch file from G_DIFFEXT + G_PATCHFILE=$G_TMP_DIR/$G_HOTPATCH_ID.patch + rm -rf $G_PATCHFILE + cd $G_PATCH_SRC &>/dev/null + l_change_file=($(find -L -name "*$G_DIFFEXT" | xargs readlink -f 2>/dev/null| sort | uniq)) + echo "detect change files:${l_change_file[@]}" + for file in ${l_change_file[@]}; + do + file="./${file#$(readlink -f $G_PATCH_SRC)}" + orig_file=${file%$G_DIFFEXT} + if [ "${orig_file##*.}" == "h" ]; then + existflag=1 && break + fi + diff -u $orig_file $file >> $G_PATCHFILE + done + cd - &>/dev/null + if [ ${existflag} -eq 1 ]; then + echo "error: do not modify the header file" + return 1 + fi + if [ -f $G_PATCHFILE ];then + echo "make patch $G_PATCHFILE" + else + echo "no change detected" + return 1 + fi + else + cp $G_PATCHFILE $G_TMP_DIR/${G_HOTPATCH_ID}.patch + G_PATCHFILE=$G_TMP_DIR/${G_HOTPATCH_ID}.patch + fi + + + cd $G_TMP_DIR &>/dev/null + if [ -n "$G_MODULE_MAKEFILE" ];then + USERMODBUILDDIR=$(dirname $G_MODULE_MAKEFILE) + fi + export USERMODBUILDDIR + export USERMODFLAGS=`cat $G_KPATCH_FLAGS` + export NO_PROFILING_CALLS=yes + kpatch-build -s $G_KERNEL_SRC $l_extra_module -c $G_KERNEL_CONFIG -v $G_VMLINUX --skip-gcc-check -n "${G_PREFIX}_${G_HOTPATCH_ID}" -b /lib/modules/`uname -r`/build $G_DEBUG_INFO $G_PATCHFILE + l_ret=$? + cd - &>/dev/null + if [ $l_ret -eq 0 ] && [ -f "$G_TMP_DIR/$G_HOTPATCH" ];then + if grep -q "CONFIG_MODULE_SIG=y" .config ;then + echo "kernel compile with CONFIG_MODULE_SIG=y,please sign the patch module" + fi + cd /tmp &>/dev/null + l_env_file=$G_TMP_DIR/toolenv + if [ -n "`which rpm 2>/dev/null`" ]; then + echo "------------------------------------------------------------------------ " > "${l_env_file}" + echo >> "${l_env_file}" + echo "The kpatch tool version info and release date:" >> "${l_env_file}" + rpm -qi kpatch >> "${l_env_file}" + echo >> "${l_env_file}" + echo "------------------------------------------------------------------------ " >> "${l_env_file}" + else + echo "------------------------------------------------------------------------ " >> "${l_env_file}" + fi + + echo >> "${l_env_file}" + echo "The hotpatch build time:" >> "${l_env_file}" + echo "`date '+%Y-%m-%d %H:%M:%S'`" >> "${l_env_file}" + echo >> "${l_env_file}" + echo "------------------------------------------------------------------------ " >> "${l_env_file}" + + if [ -f "/etc/EulerLinux.conf" ]; then + echo >> "${l_env_file}" + echo "The euler compile env version info:" >> "${l_env_file}" + cat /etc/EulerLinux.conf >> "${l_env_file}" + echo >> "${l_env_file}" + echo "------------------------------------------------------------------------ " >> "${l_env_file}" + fi + + if [ -n "${G_MODULE_SRC}" ]; then + echo >> "${l_env_file}" + echo "The module hotpatch compile path info:" >> "${l_env_file}" + echo "MODULE_SRC=${G_MODULE_SRC}" >> "${l_env_file}" + echo "MODULE_MAKEFILE=${G_MODULE_MAKEFILE}" >> "${l_env_file}" + echo >> "${l_env_file}" + echo "------------------------------------------------------------------------ " >> "${l_env_file}" + fi + + if [ -f "${G_EXT_FLAGS}" ]; then + echo >> "${l_env_file}" + echo "The module hotpatch compile flags info:" >> "${l_env_file}" + cat "${G_EXT_FLAGS}" >> "${l_env_file}" + echo >> "${l_env_file}" + echo "------------------------------------------------------------------------ " >> "${l_env_file}" + fi + + if [ -n "${G_DEBUG_INFO}" ]; then + echo >> "${l_env_file}" + echo "The debug option info:" >> "${l_env_file}" + echo "${G_DEBUG_INFO}" >> "${l_env_file}" + echo >> "${l_env_file}" + echo "------------------------------------------------------------------------ " >> "${l_env_file}" + fi + + tar -czf $G_HOTPATCH_TAR ${G_PREFIX}_${G_HOTPATCH_ID} + mv ${G_HOTPATCH_TAR} ${G_HOTPATCH_DIR} + cd - &>/dev/null + if [ $? -ne 0 ];then + echo "error: move ${G_HOTPATCH} to ${G_KSPLICE_HOTPATCH} failed" + return 1 + fi + else + echo "error: invoke kpatch-build shell script to build patch failed" + return 1 + fi + +} +######################################################### +# Description: main +# Input: +# Return: 0-success,1-failed +######################################################### +function fn_main() +{ + local ret= + local pid= + fn_verify_input $@ + if [ $? -ne 0 ]; then + fn_do_clean + return 1 + fi + + fn_makepatch + if [ $? -ne 0 ]; then + fn_do_clean + return 1 + fi + + fn_do_clean + + return 0 + +} + +function fn_prepare() +{ + kerver=`uname -r` + kerver=${kerver%.x86_64} + kerver=${kerver%.aarch64} + echo kernel version:$kerver + if [ ! -L kernel-source ];then + if [ -d /arm/arm_kernel ];then + ln -s /arm/arm_kernel/linux-$kerver kernel-source + else + ln -s /usr/src/kernels/linux-$kerver kernel-source + cp /lib/modules/`uname -r`/build/Makefile /usr/src/kernels/linux-$kerver + fi + fi + if [ ! -L .config ];then + if [ -d /arm/arm_kernel ];then + ln -s /arm/arm_kernel/linux-$kerver/.config .config + else + ln -s /usr/src/kernels/linux-$kerver/.config .config + cp /lib/modules/`uname -r`/build/.config /usr/src/kernels/linux-$kerver + fi + fi + rm -rf $G_KPATCH_FLAGS + touch $G_KPATCH_FLAGS +} + +G_NUM=`pidof -x make_hotpatch | wc -w` +if [ $G_NUM -gt 2 ];then + echo "[$0]someone is making, please try again later." + exit 1 +fi + +fn_prepare +fn_main $@ +exit $? diff --git a/os_hotpatch b/os_hotpatch new file mode 100644 index 0000000..48b50b7 --- /dev/null +++ b/os_hotpatch @@ -0,0 +1,337 @@ +#!/bin/sh +# Copyright (C) 2019. Huawei Technologies Co., Ltd. All rights reserved. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 and +# only version 2 as published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +SYS_LIVEPATCH=/sys/kernel/livepatch +G_TMP_DIR=/tmp/hotpatch.$$ +G_PATCH_FILE= + +######################################################### +# Description: usage +# Input: +# Return: 0-success +######################################################### +OS_HP_HELP() +{ + echo "usage: os_hotpatch" + echo "-w|--check : check hotpatch" + echo "-l|--load : load hotpatch" + echo "-a|--active : active hotpatch" + echo "-r|--rollback : rollback/deactive hotpatch" + echo "-d|--delete : delete/unload hotpatch" + echo "-q|--query /all : query hotpatch" + echo "-h|--help : show this help information" +} + +######################################################### +# Description: check hotpatch file before install +# Input: +# $1: hotpatch file path +# Return: 0-success,1-failed +######################################################### +OS_HP_CHECK() +{ + path=$1 + if [ ! -f "$path" ]; then + echo "The file $path is not exit" + exit 1; + fi + EXTRACT_HP $path + if [ $? -ne 0 -o ! -f "$G_PATCH_FILE" ];then + echo "The file $path is invalid" + CLEAN_UP + exit 1; + fi + CLEAN_UP + echo "The file $path is valid" + exit 0 +} + +######################################################### +# Description: active a hotpatch +# Input: +# $1: hotpatch name(klp-xxx.tar.gz) +# Return: 0-success,1-failed +######################################################### +OS_HP_ACTIVE() +{ + file=$1 + patch_name=`echo ${file%.tar.gz}|tr '-' '_'` + patch_install=`lsmod | grep -w $patch_name` + + if [ "$patch_install" == "" ]; then + echo "patch $file not load" + exit 1 + fi + + is_active=`cat ${SYS_LIVEPATCH}/${patch_name}/enabled` + if [ ${is_active} == 1 ]; then + echo "patch already active" + exit 0 + fi + + echo 1 > ${SYS_LIVEPATCH}/${patch_name}/enabled + is_active=`cat ${SYS_LIVEPATCH}/${patch_name}/enabled` + if [ ${is_active} == 1 ]; then + echo "active patch $file success" + exit 0 + else + echo "active patch $file fail" + exit 1 + fi +} + +######################################################### +# Description: deactive a hotpatch +# Input: +# $1: hotpatch name(klp-xxx.tar.gz) +# Return: 0-success,1-failed +######################################################### +OS_HP_DEACTIVE() +{ + file=$1 + patch_name=`echo ${file%.tar.gz}|tr '-' '_'` + patch_install=`lsmod | grep -w $patch_name` + + if [ "$patch_install" == "" ]; then + echo "patch $file not load" + exit 1 + fi + + is_active=`cat ${SYS_LIVEPATCH}/${patch_name}/enabled` + if [ ${is_active} == 0 ]; then + echo "patch $file already deactive" + exit 0 + else + echo 0 > ${SYS_LIVEPATCH}/${patch_name}/enabled + is_active=`cat ${SYS_LIVEPATCH}/${patch_name}/enabled` + if [ ${is_active} != 1 ]; then + echo "deactive patch $file success" + exit 0 + else + echo "deactive patch $file fail" + exit 1 + fi + fi +} + +######################################################### +# Description: remove a hotpatch +# Input: +# $1: hotpatch name(klp-xxx.tar.gz) +# Return: 0-success,1-failed +######################################################### +OS_HP_REMOVE() +{ + file=$1 + patch_name=`echo ${file%.tar.gz}|tr '-' '_'` + patch_install=`lsmod | grep -w $patch_name` + + if [ "$patch_install" == "" ]; then + echo "patch $file not load" + exit 1 + fi + + is_active=`cat ${SYS_LIVEPATCH}/${patch_name}/enabled` + if [ ${is_active} == 0 ]; then + rmmod ${patch_name} + else + echo 0 > ${SYS_LIVEPATCH}/${patch_name}/enabled + rmmod ${patch_name} + fi + + patch_install=`lsmod | grep -w $patch_name` + if [ "$patch_install" == "" ]; then + echo "remove patch $file success" + exit 0 + else + echo "remove patch $file failed" + exit 1 + fi +} + +######################################################### +# Description: query a hotpatch +# Input: +# $1: hotpatch name(klp-xxx.tar.gz) or all +# Return: 0-success,1-not load,2-deactive,3-active,4-fault +######################################################### +OS_HP_INQUIRY() +{ + file=$1 + lret=0 + if [ "all" == $file ];then + cd ${SYS_LIVEPATCH} + if [ -z "`ls -d */ 2>/dev/null`" ];then + exit 0 + fi + for patch in `ls -d */ 2>/dev/null` + do + patch_id=${patch%/} + patch_id=${patch_id#klp_} + echo "Patch Name: ${patch_id}" + lstate=`cat /${SYS_LIVEPATCH}/${patch}/enabled 2>/dev/null` + if [ -z "$lstate" ];then + echo "Patch State: Removing" + echo "-----------------------------------------------------------" + continue + fi + if [ $lstate -eq 1 ];then + echo "Patch State: Active" + else + echo "Patch State: Deactive" + fi + cd ${SYS_LIVEPATCH}/${patch} 2>/dev/null + depends=`ls -d */ 2>/dev/null` + echo "Changes:" + ls -l ${SYS_LIVEPATCH}/${patch}/*/ 2>/dev/null|grep '^d'|awk -F ' ' '{print "\t"$9}' + echo "Denpendency: ${depends%/}" + echo "-----------------------------------------------------------" + done + exit 0 + fi + patch=`echo ${file%.tar.gz}|tr '-' '_'` + patch_install=`lsmod | grep -w $patch` + if [ "$patch_install" == "" ]; then + exit 1 + fi + patch_id=${patch%/} + patch_id=${patch_id#klp_} + echo "Patch Name: ${patch_id}" + if [ `cat /${SYS_LIVEPATCH}/${patch}/enabled` -eq 1 ];then + echo "Patch State: Active" + lret=3 + else + echo "Patch State: Deactive" + lret=2 + fi + cd ${SYS_LIVEPATCH}/${patch} + depends=`ls -d */ 2>/dev/null` + echo "Changes:" + ls -l ${SYS_LIVEPATCH}/${patch}/*/ 2>/dev/null|grep '^d'|awk -F ' ' '{print "\t"$9}' + echo "Denpendency: ${depends%/}" + echo "-----------------------------------------------------------" + + exit $lret +} +######################################################### +# Description: extract hotpatch tar to tmp dir +# Input: +# $1: hotpatch file path +# Return: 0-success,1-failed +######################################################### +EXTRACT_HP() +{ + mkdir $G_TMP_DIR + tar xzf $1 -C $G_TMP_DIR + l_ret=$? + if [ $l_ret -eq 0 ];then + #find the hotpatch module + G_PATCH_FILE=$(find $G_TMP_DIR|grep -w "klp.*\.ko") + return 0 + else + return 1 + fi +} +######################################################### +# Description: clean up the tmp dir +# Input: +# Return: none +######################################################### +CLEAN_UP() +{ + rm -rf $G_TMP_DIR +} +######################################################### +# Description: install a hotpatch +# Input: +# $1: hotpatch file path +# Return: 0-success,1-failed +######################################################### +OS_HP_INSTALL() +{ + path=$1 + + if [ ! -f "$path" ]; then + echo "The file $path is not exit" + exit 1; + fi + EXTRACT_HP $path + if [ $? -ne 0 -o ! -f "$G_PATCH_FILE" ];then + echo "The file $path is invalid!" + CLEAN_UP + exit 1; + fi + patch_name=`echo ${G_PATCH_FILE%.ko}|tr '-' '_'` + patch_name=${patch_name##*/} + patch_install=`lsmod | grep -w $patch_name` + if [ "$patch_install" == "" ]; then + echo "insmod $G_PATCH_FILE" + insmod $G_PATCH_FILE + L_RET=$? + if [ 0 -ne ${L_RET} ]; then + echo "install patch $path fail" + CLEAN_UP + return 1 + else + echo "install patch $path success" + fi + else + echo "patch $path already install" + fi + CLEAN_UP + return 0 +} + +#----------------------------main-------------------------# +if [ ! -d ${SYS_LIVEPATCH} ];then + echo "this OS does not support kernel livepatch" + exit 1 +fi +input_args=`getopt -a -o l:a:r:d:w:q: -l load:,active:,delete:,check:,rollback:,query:,help, -- "$@" 2>&1` +eval set -- "${input_args}" +while true; +do + case "$1" in + -w|--check) + OS_HP_CHECK "$2" + exit $? + ;; + -l|--load) + OS_HP_INSTALL "$2" + exit $? + ;; + -a|--active) + OS_HP_ACTIVE "$2" + exit $? + ;; + -r|--rollback) + OS_HP_DEACTIVE "$2" + exit $? + ;; + -d|--delete) + OS_HP_REMOVE "$2" + exit $? + ;; + -q|--query) + OS_HP_INQUIRY "$2" + exit $? + ;; + -h|--help) + OS_HP_HELP + exit 0 + ;; + *) + OS_HP_HELP + exit 1 + ;; + esac +done