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 ++ * ... ++ * ++ * 当C++代码发生修改时,section index可能会发生变化 ++ * 这时候我们就比对一下section index所对应的section的 ++ * name,如果相同,我们就认为这两个group是SAME ++ * */ + 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)。专为开发者提供稳定、高效、安全的云端软件开发协作平台 -无论是个人、团队、或是企业,都能够用码云实现代码托管、项目管理、协作开发。企业项目请看 [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. 提交代码 -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) 这个地址来了解码云上的优秀开源项目 -4. [GVP](https://gitee.com/gvp) 全称是码云最有价值开源项目,是码云综合评定出的优秀开源项目 -5. 码云官方提供的使用手册 [https://gitee.com/help](https://gitee.com/help) -6. 码云封面人物是一档用来展示码云会员风采的栏目 [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 0000000..1be0f4a Binary files /dev/null and b/kpatch-0.6.1.tar.gz differ 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 ij + 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