!29 sync from master

From: @henry-fan
Reviewed-by: @xiezhipeng1
Signed-off-by: @xiezhipeng1
This commit is contained in:
openeuler-ci-bot 2021-04-08 14:21:14 +08:00 committed by Gitee
commit 39eb10d00b
6 changed files with 508 additions and 7 deletions

View File

@ -0,0 +1,44 @@
From aef88b0908ee9d36131c63493c02359a04d1304c Mon Sep 17 00:00:00 2001
From: Zhipeng Xie <xiezhipeng1@huawei.com>
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 <xiezhipeng1@huawei.com>
---
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

View File

@ -0,0 +1,129 @@
From 737ab3efcde45cde5fbe43ee977fc18b6912f356 Mon Sep 17 00:00:00 2001
From: Zhipeng Xie <xiezhipeng1@huawei.com>
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 <xiezhipeng1@huawei.com>
---
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

View File

@ -0,0 +1,110 @@
From 0e08aa99583573953367d5c1ec21901325c7faee Mon Sep 17 00:00:00 2001
From: Zhipeng Xie <xiezhipeng1@huawei.com>
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 <xiezhipeng1@huawei.com>
---
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 <linux/jiffies.h>
#include <linux/version.h>
+#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

172
README.md Normal file
View File

@ -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
```

View File

@ -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<xiezhipeng1@huawei.com> -1:0.9.1-6
* Wed Feb 10 2021 Zhipeng Xie<xiezhipeng1@huawei.com> -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<xiezhipeng1@huawei.com> -1:0.9.1-11
- Type:enhancement
- ID:NA
- SUG:NA
- DESC:add kpatch requires
* Tue Jan 5 2021 Zhipeng Xie<xiezhipeng1@huawei.com> -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<xiezhipeng1@huawei.com> -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<xiezhipeng1@huawei.com> -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<xiezhipeng1@huawei.com> -1:0.9.1-7
- Type:enhancement
- ID:NA
- SUG:NA
- DESC:optimize for out of tree module
* Thu Nov 12 2020 Zhipeng Xie<xiezhipeng1@huawei.com> -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<xiezhipeng1@huawei.com> - 2.0-3.1.17
* Fri Sep 27 2019 Zhipeng Xie<xiezhipeng1@huawei.com> - 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<robin.yb@huawei.com> - 2.0-3.1.13
* Tue Jul 16 2019 yangbin<robin.yb@huawei.com> - 2.0-3.1.13
- Type:enhancement
- ID:NA
- SUG:restart

View File

@ -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