hulk inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I8MGE6
--------------------------------
Currently livepatch implementation is based on ftrace, and coming patches will introduce a new solution without ftrace which will use config CONFIG_LIVEPATCH_WO_FTRACE.
Implements livepatch without ftrace by direct jump, we directly modify the first few instructions(usually one, but four for long jumps under ARM64) of the old function as jump instructions by stop_machine, so it will jump to the first address of the new function when livepatch enable
KERNEL/MODULE call/bl A---------------old_A------------ | jump new_A----+--------| | | | | | | ----------------- | | | | livepatch_module------------- | | | | |new_A <--------------------+--------------------| | | | | |---------------------------| | .plt | | ......PLTS for livepatch | -----------------------------
Something we need to consider under different architectures:
1. jump instruction 2. partial relocation in new function requires for livepatch. 3. long jumps may be required if the jump address exceeds the offset. both for livepatch relocation and livepatch enable.
So isolate ftrace based codes with config CONFIG_LIVEPATCH_FTRACE, then make livepatch solutions optional so that users can select between solutions later.
Note that, in this patch, the new solution that without ftrace isn't implemented, but just enable its config CONFIG_LIVEPATCH_WO_FTRACE on x86_64 to ensure that there is no compile problems.
Signed-off-by: Cheng Jian cj.chengjian@huawei.com Signed-off-by: Wang ShaoBo bobo.shaobowang@huawei.com Signed-off-by: Dong Kai dongkai11@huawei.com Signed-off-by: Ye Weihua yeweihua4@huawei.com Signed-off-by: Zheng Yejian zhengyejian1@huawei.com --- Documentation/filesystems/proc.rst | 2 +- arch/powerpc/Kconfig | 4 +- arch/s390/Kconfig | 2 +- arch/s390/configs/debug_defconfig | 1 + arch/s390/configs/defconfig | 1 + arch/x86/Kconfig | 3 +- arch/x86/configs/openeuler_defconfig | 3 +- arch/x86/kernel/module.c | 2 +- include/linux/livepatch.h | 21 ++++++++++ include/linux/livepatch_sched.h | 6 +-- include/linux/moduleloader.h | 2 +- kernel/livepatch/Kconfig | 48 ++++++++++++++++++++-- kernel/livepatch/Makefile | 2 +- lib/Kconfig.debug | 2 +- samples/Kconfig | 2 +- tools/testing/selftests/bpf/config.aarch64 | 1 + tools/testing/selftests/bpf/config.s390x | 1 + tools/testing/selftests/livepatch/README | 1 + tools/testing/selftests/livepatch/config | 1 + 19 files changed, 87 insertions(+), 18 deletions(-)
diff --git a/Documentation/filesystems/proc.rst b/Documentation/filesystems/proc.rst index 2b59cff8be17..65e0556064d6 100644 --- a/Documentation/filesystems/proc.rst +++ b/Documentation/filesystems/proc.rst @@ -2111,7 +2111,7 @@ permissions on the task specified to change its timerslack_ns value.
3.11 /proc/<pid>/patch_state - Livepatch patch operation state ----------------------------------------------------------------- -When CONFIG_LIVEPATCH is enabled, this file displays the value of the +When CONFIG_LIVEPATCH_FTRACE is enabled, this file displays the value of the patch state for the task.
A value of '-1' indicates that no patch is in transition. diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index d5d5388973ac..165146badfe4 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -25,7 +25,7 @@ config 64BIT
config LIVEPATCH_64 def_bool PPC64 - depends on LIVEPATCH + depends on LIVEPATCH_FTRACE
config MMU bool @@ -256,7 +256,7 @@ config PPC select HAVE_KPROBES_ON_FTRACE select HAVE_KRETPROBES select HAVE_LD_DEAD_CODE_DATA_ELIMINATION if HAVE_OBJTOOL_MCOUNT && (!ARCH_USING_PATCHABLE_FUNCTION_ENTRY || (!CC_IS_GCC || GCC_VERSION >= 110100)) - select HAVE_LIVEPATCH if HAVE_DYNAMIC_FTRACE_WITH_REGS + select HAVE_LIVEPATCH_FTRACE if HAVE_DYNAMIC_FTRACE_WITH_REGS select HAVE_MOD_ARCH_SPECIFIC select HAVE_NMI if PERF_EVENTS || (PPC64 && PPC_BOOK3S) select HAVE_OPTPROBES diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig index ae29e4392664..a663dc1a3538 100644 --- a/arch/s390/Kconfig +++ b/arch/s390/Kconfig @@ -194,7 +194,7 @@ config S390 select HAVE_KPROBES_ON_FTRACE select HAVE_KRETPROBES select HAVE_KVM - select HAVE_LIVEPATCH + select HAVE_LIVEPATCH_FTRACE select HAVE_MEMBLOCK_PHYS_MAP select HAVE_MOD_ARCH_SPECIFIC select HAVE_NMI diff --git a/arch/s390/configs/debug_defconfig b/arch/s390/configs/debug_defconfig index 438cd92e6080..ea93ed91211d 100644 --- a/arch/s390/configs/debug_defconfig +++ b/arch/s390/configs/debug_defconfig @@ -44,6 +44,7 @@ CONFIG_KEXEC_FILE=y CONFIG_KEXEC_SIG=y CONFIG_CRASH_DUMP=y CONFIG_LIVEPATCH=y +CONFIG_LIVEPATCH_FTRACE=y CONFIG_MARCH_ZEC12=y CONFIG_TUNE_ZEC12=y CONFIG_NR_CPUS=512 diff --git a/arch/s390/configs/defconfig b/arch/s390/configs/defconfig index 1b8150e50f6a..cab45afd11c0 100644 --- a/arch/s390/configs/defconfig +++ b/arch/s390/configs/defconfig @@ -42,6 +42,7 @@ CONFIG_KEXEC_FILE=y CONFIG_KEXEC_SIG=y CONFIG_CRASH_DUMP=y CONFIG_LIVEPATCH=y +CONFIG_LIVEPATCH_FTRACE=y CONFIG_MARCH_ZEC12=y CONFIG_TUNE_ZEC12=y CONFIG_NR_CPUS=512 diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 66bfabae8814..4ff6c115d127 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -241,7 +241,8 @@ config X86 select HAVE_KRETPROBES select HAVE_RETHOOK select HAVE_KVM - select HAVE_LIVEPATCH if X86_64 + select HAVE_LIVEPATCH_FTRACE if X86_64 + select HAVE_LIVEPATCH_WO_FTRACE if X86_64 select HAVE_MIXED_BREAKPOINTS_REGS select HAVE_MOD_ARCH_SPECIFIC select HAVE_MOVE_PMD diff --git a/arch/x86/configs/openeuler_defconfig b/arch/x86/configs/openeuler_defconfig index 507d199ff598..869debbed9a7 100644 --- a/arch/x86/configs/openeuler_defconfig +++ b/arch/x86/configs/openeuler_defconfig @@ -499,8 +499,9 @@ CONFIG_LEGACY_VSYSCALL_XONLY=y # CONFIG_CMDLINE_BOOL is not set CONFIG_MODIFY_LDT_SYSCALL=y # CONFIG_STRICT_SIGALTSTACK_SIZE is not set -CONFIG_HAVE_LIVEPATCH=y +CONFIG_HAVE_LIVEPATCH_FTRACE=y CONFIG_LIVEPATCH=y +CONFIG_LIVEPATCH_FTRACE=y # end of Processor type and features
CONFIG_FUNCTION_PADDING_CFI=11 diff --git a/arch/x86/kernel/module.c b/arch/x86/kernel/module.c index 5f71a0cf4399..9b75f1e02d60 100644 --- a/arch/x86/kernel/module.c +++ b/arch/x86/kernel/module.c @@ -258,7 +258,7 @@ int apply_relocate_add(Elf64_Shdr *sechdrs, return write_relocate_add(sechdrs, strtab, symindex, relsec, me, true); }
-#ifdef CONFIG_LIVEPATCH +#ifdef CONFIG_LIVEPATCH_FTRACE void clear_relocate_add(Elf64_Shdr *sechdrs, const char *strtab, unsigned int symindex, diff --git a/include/linux/livepatch.h b/include/linux/livepatch.h index 9b9b38e89563..2c6ce24b641a 100644 --- a/include/linux/livepatch.h +++ b/include/linux/livepatch.h @@ -194,6 +194,7 @@ struct klp_patch {
int klp_enable_patch(struct klp_patch *);
+#ifdef CONFIG_LIVEPATCH_FTRACE /* Called from the module loader during module coming/going states */ int klp_module_coming(struct module *mod); void klp_module_going(struct module *mod); @@ -235,6 +236,26 @@ int klp_apply_section_relocs(struct module *pmod, Elf_Shdr *sechdrs, unsigned int symindex, unsigned int secindex, const char *objname);
+#else /* !CONFIG_LIVEPATCH_FTRACE */ + +static inline int klp_module_coming(struct module *mod) { return 0; } +static inline void klp_module_going(struct module *mod) {} +static inline bool klp_patch_pending(struct task_struct *task) { return false; } +static inline void klp_update_patch_state(struct task_struct *task) {} +static inline void klp_copy_process(struct task_struct *child) {} +static inline bool klp_have_reliable_stack(void) { return true; } + +static inline +int klp_apply_section_relocs(struct module *pmod, Elf_Shdr *sechdrs, + const char *shstrtab, const char *strtab, + unsigned int symindex, unsigned int secindex, + const char *objname) +{ + return 0; +} + +#endif /* CONFIG_LIVEPATCH_FTRACE */ + #else /* !CONFIG_LIVEPATCH */
static inline int klp_module_coming(struct module *mod) { return 0; } diff --git a/include/linux/livepatch_sched.h b/include/linux/livepatch_sched.h index 013794fb5da0..7fe69bb59a16 100644 --- a/include/linux/livepatch_sched.h +++ b/include/linux/livepatch_sched.h @@ -5,7 +5,7 @@ #include <linux/jump_label.h> #include <linux/static_call_types.h>
-#ifdef CONFIG_LIVEPATCH +#ifdef CONFIG_LIVEPATCH_FTRACE
void __klp_sched_try_switch(void);
@@ -21,9 +21,9 @@ static __always_inline void klp_sched_try_switch(void)
#endif /* !CONFIG_PREEMPT_DYNAMIC || !CONFIG_HAVE_PREEMPT_DYNAMIC_CALL */
-#else /* !CONFIG_LIVEPATCH */ +#else /* !CONFIG_LIVEPATCH_FTRACE */ static inline void klp_sched_try_switch(void) {} static inline void __klp_sched_try_switch(void) {} -#endif /* CONFIG_LIVEPATCH */ +#endif /* CONFIG_LIVEPATCH_FTRACE */
#endif /* _LINUX_LIVEPATCH_SCHED_H_ */ diff --git a/include/linux/moduleloader.h b/include/linux/moduleloader.h index 001b2ce83832..068362e08747 100644 --- a/include/linux/moduleloader.h +++ b/include/linux/moduleloader.h @@ -80,7 +80,7 @@ int apply_relocate_add(Elf_Shdr *sechdrs, unsigned int symindex, unsigned int relsec, struct module *mod); -#ifdef CONFIG_LIVEPATCH +#ifdef CONFIG_LIVEPATCH_FTRACE /* * Some architectures (namely x86_64 and ppc64) perform sanity checks when * applying relocations. If a patched module gets unloaded and then later diff --git a/kernel/livepatch/Kconfig b/kernel/livepatch/Kconfig index 53d51ed619a3..8ffe3b9ca1f9 100644 --- a/kernel/livepatch/Kconfig +++ b/kernel/livepatch/Kconfig @@ -1,16 +1,22 @@ # SPDX-License-Identifier: GPL-2.0-only -config HAVE_LIVEPATCH +config HAVE_LIVEPATCH_FTRACE bool help - Arch supports kernel live patching + Arch supports kernel live patching based on ftrace + +config HAVE_LIVEPATCH_WO_FTRACE + bool + help + Arch supports kernel live patching without ftrace + +menu "Enable Livepatch"
config LIVEPATCH bool "Kernel Live Patching" - depends on DYNAMIC_FTRACE_WITH_REGS || DYNAMIC_FTRACE_WITH_ARGS + depends on (HAVE_LIVEPATCH_FTRACE && (DYNAMIC_FTRACE_WITH_REGS || DYNAMIC_FTRACE_WITH_ARGS)) || HAVE_LIVEPATCH_WO_FTRACE depends on MODULES depends on SYSFS depends on KALLSYMS_ALL - depends on HAVE_LIVEPATCH depends on !TRIM_UNUSED_KSYMS help Say Y here if you want to support kernel live patching. @@ -18,3 +24,37 @@ config LIVEPATCH module uses the interface provided by this option to register a patch, causing calls to patched functions to be redirected to new function code contained in the patch module. + +choice + prompt "live patching method" + depends on LIVEPATCH + help + Live patching implementation method configuration. + Choose an interested live patching solution which will + allow calls to patched functions to be redirected to new + function code contained in the patch module. + +config LIVEPATCH_FTRACE + bool "based on ftrace" + depends on HAVE_LIVEPATCH_FTRACE + help + Supports kernel live patching based on ftrace. + This is the original implementation of kernel live + patching which is just renamed to distinguish from + another live patching solution. + +config LIVEPATCH_WO_FTRACE + bool "without ftrace" + depends on HAVE_LIVEPATCH_WO_FTRACE + help + Supports kernel live patching without ftrace. + This solution will patch the first few instructions + of a function so that caller of it will jump to + another expected function. + Note that this patching solution would not handle conflict + with other patching technologies (i.e. ftrace, kprobe), + please avoid acting them on the same function! + +endchoice + +endmenu diff --git a/kernel/livepatch/Makefile b/kernel/livepatch/Makefile index cf03d4bdfc66..18f9cb687576 100644 --- a/kernel/livepatch/Makefile +++ b/kernel/livepatch/Makefile @@ -1,4 +1,4 @@ # SPDX-License-Identifier: GPL-2.0-only -obj-$(CONFIG_LIVEPATCH) += livepatch.o +obj-$(CONFIG_LIVEPATCH_FTRACE) += livepatch.o
livepatch-objs := core.o patch.o shadow.o state.o transition.o diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index fa307f93fa2e..9e6784fa97ac 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -2866,7 +2866,7 @@ config TEST_LIVEPATCH tristate "Test livepatching" default n depends on DYNAMIC_DEBUG - depends on LIVEPATCH + depends on LIVEPATCH_FTRACE depends on m help Test kernel livepatching features for correctness. The tests will diff --git a/samples/Kconfig b/samples/Kconfig index b0ddf5f36738..db611889bd11 100644 --- a/samples/Kconfig +++ b/samples/Kconfig @@ -130,7 +130,7 @@ config SAMPLE_RPMSG_CLIENT
config SAMPLE_LIVEPATCH tristate "Build live patching samples -- loadable modules only" - depends on LIVEPATCH && m + depends on LIVEPATCH_FTRACE && m help Build sample live patch demonstrations.
diff --git a/tools/testing/selftests/bpf/config.aarch64 b/tools/testing/selftests/bpf/config.aarch64 index 253821494884..279df18b29c4 100644 --- a/tools/testing/selftests/bpf/config.aarch64 +++ b/tools/testing/selftests/bpf/config.aarch64 @@ -90,6 +90,7 @@ CONFIG_KRETPROBES=y CONFIG_KSM=y CONFIG_LATENCYTOP=y CONFIG_LIVEPATCH=y +CONFIG_LIVEPATCH_FTRACE=y CONFIG_LOCK_STAT=y CONFIG_MACVLAN=y CONFIG_MACVTAP=y diff --git a/tools/testing/selftests/bpf/config.s390x b/tools/testing/selftests/bpf/config.s390x index 2ba92167be35..90fc5ba62fe2 100644 --- a/tools/testing/selftests/bpf/config.s390x +++ b/tools/testing/selftests/bpf/config.s390x @@ -73,6 +73,7 @@ CONFIG_KRETPROBES=y CONFIG_KSM=y CONFIG_LATENCYTOP=y CONFIG_LIVEPATCH=y +CONFIG_LIVEPATCH_FTRACE=y CONFIG_LOCK_STAT=y CONFIG_MACVLAN=y CONFIG_MACVTAP=y diff --git a/tools/testing/selftests/livepatch/README b/tools/testing/selftests/livepatch/README index 0942dd5826f8..40a2596e65c2 100644 --- a/tools/testing/selftests/livepatch/README +++ b/tools/testing/selftests/livepatch/README @@ -16,6 +16,7 @@ Config Set these config options and their prerequisites:
CONFIG_LIVEPATCH=y +CONFIG_LIVEPATCH_FTRACE=y CONFIG_TEST_LIVEPATCH=m
diff --git a/tools/testing/selftests/livepatch/config b/tools/testing/selftests/livepatch/config index ad23100cb27c..ee54bc7e631e 100644 --- a/tools/testing/selftests/livepatch/config +++ b/tools/testing/selftests/livepatch/config @@ -1,3 +1,4 @@ CONFIG_LIVEPATCH=y +CONFIG_LIVEPATCH_FTRACE=y CONFIG_DYNAMIC_DEBUG=y CONFIG_TEST_LIVEPATCH=m