From 0dfb225fd98949abde139d477ef0656047146898 Mon Sep 17 00:00:00 2001 From: Wentao Fan Date: Thu, 8 Apr 2021 02:13:07 -0400 Subject: [PATCH] sync from master Signed-off-by: Wentao Fan --- 0024-optimize-for-out-of-tree-module.patch | 44 +++++ ...ot-resolved-when-new-functions-expor.patch | 129 +++++++++++++ ...tatic-variables-using-KPATCH_IGNORE_.patch | 110 +++++++++++ README.md | 172 ++++++++++++++++++ kpatch.spec | 49 ++++- make_hotpatch | 11 +- 6 files changed, 508 insertions(+), 7 deletions(-) create mode 100644 0024-optimize-for-out-of-tree-module.patch create mode 100644 0025-Fix-relocation-not-resolved-when-new-functions-expor.patch create mode 100644 0026-support-remove-static-variables-using-KPATCH_IGNORE_.patch create mode 100644 README.md diff --git a/0024-optimize-for-out-of-tree-module.patch b/0024-optimize-for-out-of-tree-module.patch new file mode 100644 index 0000000..032ca83 --- /dev/null +++ b/0024-optimize-for-out-of-tree-module.patch @@ -0,0 +1,44 @@ +From aef88b0908ee9d36131c63493c02359a04d1304c Mon Sep 17 00:00:00 2001 +From: Zhipeng Xie +Date: Fri, 13 Nov 2020 03:05:22 -0500 +Subject: [PATCH] optimize for out of tree module + +some out-of-tree modules's Module.symvers not in SRCDIR +some out-of-tree modules's obj has relative path like /xxx/./xxx.o + +Signed-off-by: Zhipeng Xie +--- + kpatch-build/kpatch-build | 1 + + kpatch-build/kpatch-gcc | 4 +++- + 2 files changed, 4 insertions(+), 1 deletion(-) + +diff --git a/kpatch-build/kpatch-build b/kpatch-build/kpatch-build +index 523d5df..6238bc8 100755 +--- a/kpatch-build/kpatch-build ++++ b/kpatch-build/kpatch-build +@@ -1035,6 +1035,7 @@ for i in $FILES; do + BUILDDIR="/lib/modules/$ARCHVERSION/build/" + SYMVERS_FILE="$TEMPDIR/Module.symvers" + [[ -e $SRCDIR/Module.symvers ]] && cp "$SRCDIR/Module.symvers" "$SYMVERS_FILE" ++ [[ -e $USERMODBUILDDIR/Module.symvers ]] && cp "$USERMODBUILDDIR/Module.symvers" $SYMVERS_FILE + awk '{ print $1 "\t" $2 "\t" $3 "\t" $4}' "${BUILDDIR}/Module.symvers" >> "$SYMVERS_FILE" + fi + fi +diff --git a/kpatch-build/kpatch-gcc b/kpatch-build/kpatch-gcc +index 6ad6ebc..2b2490e 100755 +--- a/kpatch-build/kpatch-gcc ++++ b/kpatch-build/kpatch-gcc +@@ -25,7 +25,9 @@ if [[ "$TOOLCHAINCMD" =~ "${ARCH_COMPILE}gcc" || + + [[ "$obj" = */.tmp_*.o ]] && obj="${obj/.tmp_/}" + relobj=${obj//$KPATCH_GCC_SRCDIR\//} +- case "$relobj" in ++ tmpobj=$(readlink -f $obj) ++ relobj2=${tmpobj//$KPATCH_GCC_SRCDIR\//} ++ case "$relobj2" in + *.mod.o|\ + *built-in.o|\ + *built-in.a|\ +-- +2.18.1 + diff --git a/0025-Fix-relocation-not-resolved-when-new-functions-expor.patch b/0025-Fix-relocation-not-resolved-when-new-functions-expor.patch new file mode 100644 index 0000000..670a5ba --- /dev/null +++ b/0025-Fix-relocation-not-resolved-when-new-functions-expor.patch @@ -0,0 +1,129 @@ +From 737ab3efcde45cde5fbe43ee977fc18b6912f356 Mon Sep 17 00:00:00 2001 +From: Zhipeng Xie +Date: Sun, 22 Nov 2020 21:40:39 +0800 +Subject: [PATCH] Fix relocation not resolved when new functions exported only + +When no functions changed and new functions exported, kobject is not +created, so livepatch will not call klp_init_object and relocation +in new functions are not resolved. + +Signed-off-by: Zhipeng Xie +--- + kmod/patch/kpatch-patch.h | 4 ++++ + kmod/patch/kpatch.lds.S | 6 ++++++ + kmod/patch/livepatch-patch-hook.c | 19 +++++++++++++++++++ + kpatch-build/create-diff-object.c | 24 ++++++++++++++++++++++++ + 4 files changed, 53 insertions(+) + +diff --git a/kmod/patch/kpatch-patch.h b/kmod/patch/kpatch-patch.h +index 6e39364..33f2056 100644 +--- a/kmod/patch/kpatch-patch.h ++++ b/kmod/patch/kpatch-patch.h +@@ -63,6 +63,10 @@ struct kpatch_post_unpatch_callback { + void (*callback)(void *obj); + char *objname; + }; ++struct kpatch_object { ++ char *objname; ++}; + + extern unsigned long __kpatch_force_funcs[], __kpatch_force_funcs_end[]; ++extern struct kpatch_object __kpatch_objects[], __kpatch_objects_end[]; + #endif /* _KPATCH_PATCH_H_ */ +diff --git a/kmod/patch/kpatch.lds.S b/kmod/patch/kpatch.lds.S +index bc5de82..4c4d77b 100644 +--- a/kmod/patch/kpatch.lds.S ++++ b/kmod/patch/kpatch.lds.S +@@ -47,4 +47,10 @@ SECTIONS + __kpatch_force_funcs_end = . ; + QUAD(0); + } ++ .kpatch.objects : { ++ __kpatch_objects = . ; ++ *(.kpatch.objects) ++ __kpatch_objects_end = . ; ++ QUAD(0); ++ } + } +diff --git a/kmod/patch/livepatch-patch-hook.c b/kmod/patch/livepatch-patch-hook.c +index 5a0de7f..d3fb1db 100644 +--- a/kmod/patch/livepatch-patch-hook.c ++++ b/kmod/patch/livepatch-patch-hook.c +@@ -249,6 +249,22 @@ static int patch_is_func_forced(unsigned long addr) + return 0; + } + ++static int add_kpatch_objects(void) ++{ ++ struct kpatch_object *p_kpatch_object; ++ struct patch_object *object; ++ ++ for (p_kpatch_object = __kpatch_objects; ++ p_kpatch_object < __kpatch_objects_end; ++ p_kpatch_object++) { ++ object = patch_find_object_by_name(p_kpatch_object->objname); ++ if (!object) ++ return -ENOMEM; ++ } ++ ++ return 0; ++} ++ + + #ifdef HAVE_CALLBACKS + static int add_callbacks_to_patch_objects(void) +@@ -382,6 +398,9 @@ static int __init patch_init(void) + if (ret) + goto out; + ++ ret = add_kpatch_objects(); ++ if (ret) ++ goto out; + /* past this point, only possible return code is -ENOMEM */ + ret = -ENOMEM; + +diff --git a/kpatch-build/create-diff-object.c b/kpatch-build/create-diff-object.c +index fca68b8..bea758e 100644 +--- a/kpatch-build/create-diff-object.c ++++ b/kpatch-build/create-diff-object.c +@@ -2553,6 +2553,27 @@ static void kpatch_create_kpatch_arch_section(struct kpatch_elf *kelf, char *obj + karch_sec->sh.sh_size = karch_sec->data->d_size; + } + ++static void kpatch_create_kpatch_object_section(struct kpatch_elf *kelf, char *objname) ++{ ++ struct symbol *strsym; ++ struct rela *rela; ++ struct section *kobj_sec; ++ ++ kobj_sec = create_section_pair(kelf, ".kpatch.objects", sizeof(struct kpatch_object), 1); ++ ++ /* lookup strings symbol */ ++ strsym = find_symbol_by_name(&kelf->symbols, ".kpatch.strings"); ++ if (!strsym) ++ ERROR("can't find .kpatch.strings symbol"); ++ ++ /* entries[index].objname */ ++ ALLOC_LINK(rela, &kobj_sec->rela->relas); ++ rela->sym = strsym; ++ rela->type = absolute_rela_type; ++ rela->addend = offset_of_string(&kelf->strings, objname); ++ rela->offset = (unsigned int)(offsetof(struct kpatch_object, objname)); ++} ++ + static void kpatch_process_special_sections(struct kpatch_elf *kelf) + { + struct special_section *special; +@@ -3710,6 +3731,9 @@ int main(int argc, char *argv[]) + kpatch_create_intermediate_sections(kelf_out, lookup, parent_name, patch_name); + kpatch_create_kpatch_arch_section(kelf_out, parent_name); + kpatch_create_callbacks_objname_rela(kelf_out, parent_name); ++ if (!num_changed && new_globals_exist) { ++ kpatch_create_kpatch_object_section(kelf_out, parent_name); ++ } + kpatch_build_strings_section_data(kelf_out); + + gcc_add_option = getenv("GCC_ADD_OPTION"); +-- +2.18.1 + diff --git a/0026-support-remove-static-variables-using-KPATCH_IGNORE_.patch b/0026-support-remove-static-variables-using-KPATCH_IGNORE_.patch new file mode 100644 index 0000000..a6b1270 --- /dev/null +++ b/0026-support-remove-static-variables-using-KPATCH_IGNORE_.patch @@ -0,0 +1,110 @@ +From 0e08aa99583573953367d5c1ec21901325c7faee Mon Sep 17 00:00:00 2001 +From: Zhipeng Xie +Date: Wed, 30 Dec 2020 21:13:10 -0500 +Subject: [PATCH] support remove static variables using KPATCH_IGNORE_STATIC + +Static variables will be removed due to compiler optimization. +And some static variables can be treated as new variables, such as +static variables in print limit macros. So add KPATCH_IGNORE_STATIC +to tell kpatch to treat the static variables as new variables. + +Signed-off-by: Zhipeng Xie +--- + kmod/patch/kpatch-macros.h | 3 +++ + kpatch-build/create-diff-object.c | 45 ++++++++++++++++++++++++++++++- + 2 files changed, 47 insertions(+), 1 deletion(-) + +diff --git a/kmod/patch/kpatch-macros.h b/kmod/patch/kpatch-macros.h +index a60a267..9a30d68 100644 +--- a/kmod/patch/kpatch-macros.h ++++ b/kmod/patch/kpatch-macros.h +@@ -5,6 +5,9 @@ + #include + #include + ++#define KPATCH_IGNORE_STATIC(_static) \ ++ char *__UNIQUE_ID(kpatch_ignore_static_) __section(.kpatch.ignore.statics) = _static; ++ + /* + * KPATCH_IGNORE_SECTION macro + * +diff --git a/kpatch-build/create-diff-object.c b/kpatch-build/create-diff-object.c +index a2a9cab..211ea72 100644 +--- a/kpatch-build/create-diff-object.c ++++ b/kpatch-build/create-diff-object.c +@@ -1151,6 +1151,40 @@ static int kpatch_is_normal_static_local(struct symbol *sym) + return 1; + } + ++static int kpatch_mark_ignored_statics(struct kpatch_elf *kelf, struct symbol *sym) ++{ ++ struct section *sec, *strsec; ++ struct rela *rela; ++ char *name; ++ ++ sec = find_section_by_name(&kelf->sections, ".kpatch.ignore.statics"); ++ if (!sec) ++ return 0; ++ ++ list_for_each_entry(rela, &sec->rela->relas, list) { ++ strsec = rela->sym->sec; ++ strsec->status = CHANGED; ++ /* ++ * Include the string section here. This is because the ++ * KPATCH_IGNORE_STATIC() macro is passed a literal string ++ * by the patch author, resulting in a change to the string ++ * section. If we don't include it, then we will potentially ++ * get a "changed section not included" error in ++ * kpatch_verify_patchability() if no other function based change ++ * also changes the string section. We could try to exclude each ++ * literal string added to the section by KPATCH_IGNORE_STATIC() ++ * 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; ++ if (!strncmp(name, sym->name, strlen(name))) ++ return 1; ++ } ++ ++ return 0; ++} ++ + /* + * gcc renames static local variables by appending a period and a number. For + * example, __foo could be renamed to __foo.31452. Unfortunately this number +@@ -1230,6 +1264,11 @@ static void kpatch_correlate_static_local_variables(struct kpatch_elf *base, + if (sym->twin) + continue; + ++ if (kpatch_mark_ignored_statics(patched, sym)) { ++ log_normal("KPATCH_IGNORE_STATIC:ignore static variable %s\n", sym->name); ++ continue; ++ } ++ + bundled = sym == sym->sec->sym; + if (bundled && sym->sec == sec->base) { + /* +@@ -1286,6 +1325,11 @@ static void kpatch_correlate_static_local_variables(struct kpatch_elf *base, + if (!kpatch_is_normal_static_local(sym)) + continue; + ++ if (kpatch_mark_ignored_statics(patched, sym)) { ++ log_normal("KPATCH_IGNORE_STATIC:ignore static variable %s\n", sym->name); ++ continue; ++ } ++ + if (!sym->twin || !sec->twin) + DIFF_FATAL("reference to static local variable %s in %s was removed", + sym->name, +@@ -1329,7 +1373,6 @@ static void kpatch_correlate_static_local_variables(struct kpatch_elf *base, + log_normal("WARNING: unable to correlate static local variable %s used by %s, assuming variable is new\n", + sym->name, + kpatch_section_function_name(sec)); +- return; + } + } + } +-- +2.18.1 + diff --git a/README.md b/README.md new file mode 100644 index 0000000..0682b35 --- /dev/null +++ b/README.md @@ -0,0 +1,172 @@ +openEuler内核热补丁使用指南 +---------- + +支持操作系统: + +openEuler 20.03 LTS及以上版本 + +openEuler社区已经验证支持内核热补丁的架构: + +- [x] x86_64 +- [x] arm64 +- [ ] ppc64le +- [ ] s390 +- [ ] risc-v + +上游社区: + +https://github.com/dynup/kpatch + +## 环境准备 + +安装依赖软件包 + +```bash +yum install -y make gcc patch bison flex openssl-devel kpatch kpatch-runtime +``` + +安装当前内核源码和开发包 + +```bash +yum install -y kernel-source-`uname -r` kernel-debuginfo-`uname -r` kernel-devel-`uname -r` +``` + +进入热补丁制作目录并准备环境 + +```bash +cd /opt/patch_workspace +rm -rf kernel-source .config +ln -s /usr/src/linux-`uname -r`/ kernel-source +ln -s /usr/src/linux-`uname -r`/.config .config +ln -s /usr/lib/debug/lib/modules/`uname -r`/vmlinux vmlinux +``` + +## 制作内核热补丁 + +支持两种方式制作内核热补丁 + +### 方法1:直接修改源代码的方式 + +进入内核源码目录(下面以修改fs/proc/cmdline.c文件为例) + +```bash +cd kernel-source +cd fs/proc/ +cp cmdline.c cmdline.c.new +``` +此处cp操作的后缀.new在后面执行make_hotpatch时会用到 + +修改cmdline.c.new中的函数 + +开始制作热补丁 + +```bash +cd /opt/patch_workspace/ +./make_hotpatch -d .new -i cmdline +``` + +参数 | 说明| +--------- | --------| +-d |前面cp操作时的唯一后缀名| +-i |补丁ID,可包括字母和数字| + +### 方法2:通过patch文件的方式 + +```bash +cd /opt/patch_workspace/ +./make_hotpatch -i cmdline -p cmdline.patch +``` + +参数 | 说明| +--------- | --------| +-i |补丁ID,可包括字母和数字| +-p |patch文件路径(patch文件必须支持在kernel-source路径下通过patch -p1的方式修改源码)| + +补丁制作完成,补丁文件以压缩包的格式存放于/opt/patch_workspace/hotpatch目录下 + + +## 制作第三方模块热补丁 + + +支持两种方式制作第三方模块热补丁 + +### 方法1:直接修改源代码的方式 + +进入模块源码目录(下面以https://gitee.com/openeuler/prefetch_tuning模块为例) + +```bash +git clone https://gitee.com/openeuler/prefetch_tuning +cd prefetch_tuning +cp prefetch_mod.c prefetch_mod.c.new +``` + +此处cp操作的后缀.new在后面执行make_hotpatch时会用到 + +修改prefetch_mod.c.new中的函数 + +```bash +cd /opt/patch_workspace/ +./make_hotpatch -d .new -i testmod -m `pwd`/prefetch_tuning/ +``` + +参数 | 说明| +--------- | --------| +-d |前面cp操作时的唯一后缀名| +-i |补丁ID,可包括字母和数字| +-m |第三方模块源码路径| +-f |可选,当第三方模块Makefile不在-m指定的源码目录下时,通过该参数指定Makefile的绝对路径| + +### 方法2:通过patch文件的方式 + +```bash +cd /opt/patch_workspace/ +./make_hotpatch -i testmod -m `pwd`/prefetch_tuning/ -p testmod.patch +``` + +参数 | 说明| +--------- | --------| +-i |补丁ID,可包括字母和数字| +-m |第三方模块源码路径| +-p |patch文件路径(patch文件必须支持在-m参数指定的路径下通过patch -p1的方式修改源码)| +-f |可选,当第三方模块Makefile不在-m指定的源码目录下时,通过该参数指定Makefile的绝对路径| + +第三方模块补丁补丁制作完成,补丁文件以压缩包的格式存放于/opt/patch_workspace/hotpatch目录下 + +## 管理热补丁 + +### 加载热补丁 + +```bash +livepatch -l klp_cmdline.tar.gz +``` + +### 激活热补丁 + +```bash +livepatch -a cmdline +``` + +此时热补丁已生效,缺陷函数已被修复。 + +### 回退热补丁 + +```bash +livepatch -d cmdline +``` + +### 卸载热补丁 + +```bash +livepatch -r cmdline +``` + +## 编译更新补丁工具 + +```bash +yum install -y git rpm-build elfutils-libelf-devel uname-build-checks gdb-headless +git clone https://gitee.com/src-openeuler/kpatch.git +mkdir -p ~/rpmbuild/SOURCES/ +/bin/cp kpatch/* ~/rpmbuild/SOURCES/ +rpmbuild -ba kpatch/kpatch.spec +rpm -Uvh ~/rpmbuild/RPMS/`arch`/kpatch*.rpm +``` diff --git a/kpatch.spec b/kpatch.spec index f091b96..cf383c6 100644 --- a/kpatch.spec +++ b/kpatch.spec @@ -1,7 +1,7 @@ Name: kpatch Epoch: 1 Version: 0.9.1 -Release: 6 +Release: 12 Summary: A Linux dynamic kernel patching infrastructure License: GPLv2 @@ -35,9 +35,12 @@ Patch0020:0020-kpatch-build-add-compile-flag-fno-reorder-functions.patch Patch0021:0021-kpatch-build-don-t-copy-.config-for-out-of-tree-modu.patch Patch0022:0022-support-force-enable-disable-for-x86.patch Patch0023:0023-create-diff-object-fix-duplicate-symbols-for-vmlinux.patch +Patch0024:0024-optimize-for-out-of-tree-module.patch +Patch0025:0025-Fix-relocation-not-resolved-when-new-functions-expor.patch +Patch0026:0026-support-remove-static-variables-using-KPATCH_IGNORE_.patch BuildRequires: gcc elfutils-libelf-devel uname-build-checks kernel-devel git -Requires: bc +Requires: bc make gcc patch bison flex openssl-devel Recommends: %{name}-help = %{version}-%{release} %description @@ -94,7 +97,43 @@ popd %{_mandir}/man1/*.1.gz %changelog -* Thu Nov 22 2020 Zhipeng Xie -1:0.9.1-6 +* Wed Feb 10 2021 Zhipeng Xie -1:0.9.1-12 +- Type:enhancement +- ID:NA +- SUG:NA +- DESC:modify hotpatch id length limit from 20 to 32 + +* Mon Jan 11 2021 Zhipeng Xie -1:0.9.1-11 +- Type:enhancement +- ID:NA +- SUG:NA +- DESC:add kpatch requires + +* Tue Jan 5 2021 Zhipeng Xie -1:0.9.1-10 +- Type:enhancement +- ID:NA +- SUG:NA +- DESC:only skip gcc check in cross compile environment + +* Thu Dec 31 2020 Zhipeng Xie -1:0.9.1-9 +- Type:enhancement +- ID:NA +- SUG:NA +- DESC:support remove static variables using KPATCH_IGNORE_STATIC + +* Sun Nov 22 2020 Zhipeng Xie -1:0.9.1-8 +- Type:bugfix +- ID:NA +- SUG:NA +- DESC:Fix relocation not resolved when new functions exported only + +* Tue Nov 17 2020 Zhipeng Xie -1:0.9.1-7 +- Type:enhancement +- ID:NA +- SUG:NA +- DESC:optimize for out of tree module + +* Thu Nov 12 2020 Zhipeng Xie -1:0.9.1-6 - Type:enhancement - ID:NA - SUG:NA @@ -185,7 +224,7 @@ popd - SUG:restart - DESC:add security compile flags -* Tue Sep 27 2019 Zhipeng Xie - 2.0-3.1.17 +* Fri Sep 27 2019 Zhipeng Xie - 2.0-3.1.17 - Type:enhancement - ID:NA - SUG:restart @@ -209,7 +248,7 @@ popd - SUG:NA - DESC:rewrite spec -* Fri Jul 16 2019 yangbin - 2.0-3.1.13 +* Tue Jul 16 2019 yangbin - 2.0-3.1.13 - Type:enhancement - ID:NA - SUG:restart diff --git a/make_hotpatch b/make_hotpatch index 8c06051..9612e63 100644 --- a/make_hotpatch +++ b/make_hotpatch @@ -154,7 +154,7 @@ function fn_check_reg_char() function fn_check_id() { local l_id=$1 - fn_check_reg_char "$l_id" "20" "-_" + fn_check_reg_char "$l_id" "32" "-_" if [ $? -ne 0 ];then echo "error: check hotpatch id failed" return 1 @@ -592,7 +592,14 @@ function fn_makepatch() export USERMODFLAGS=`cat $G_KPATCH_FLAGS` export NO_PROFILING_CALLS="yes" export DISABLE_AFTER_LOAD="yes" - kpatch-build -s $G_PATCH_SRC -c $G_KERNEL_CONFIG -v $G_VMLINUX --skip-gcc-check -n "${G_PREFIX}_${G_HOTPATCH_ID}" $G_DEBUG_INFO $G_PATCHFILE + UNAME_R=$(uname -r) + UNAME_R_ARCH=${UNAME_R##*.} + SKIP_GCC_CHECK="" + if [[ "${UNAME_R_ARCH}" != "$(uname -p)" ]];then + echo "build in cross compile environment, skip gcc check" + SKIP_GCC_CHECK="--skip-gcc-check" + fi + kpatch-build -s $G_PATCH_SRC -c $G_KERNEL_CONFIG -v $G_VMLINUX ${SKIP_GCC_CHECK} -n "${G_PREFIX}_${G_HOTPATCH_ID}" $G_DEBUG_INFO $G_PATCHFILE l_ret=$? cd - &>/dev/null if [ $l_ret -eq 0 ] && [ -f "$G_TMP_DIR/$G_HOTPATCH" ];then -- Gitee