hulk inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I8MGE6 CVE: NA
--------------------------------
The kpatch-build processes the __jump_table special section, and only the jump_lable used by the changed functions will be included in __jump_table section, and the livepatch should process the tracepoint again after the dynamic relocation.
NOTE: adding new tracepoints definition is not supported.
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 --- include/linux/jump_label.h | 10 ++++++++++ include/linux/module.h | 33 +++++++++++++++++++++++++++++++++ kernel/jump_label.c | 22 ++++++++++++++++++++++ kernel/livepatch/core.c | 6 ++++++ kernel/module/main.c | 8 ++++++++ 5 files changed, 79 insertions(+)
diff --git a/include/linux/jump_label.h b/include/linux/jump_label.h index f0a949b7c973..39386db201a2 100644 --- a/include/linux/jump_label.h +++ b/include/linux/jump_label.h @@ -235,6 +235,9 @@ extern void static_key_disable(struct static_key *key); extern void static_key_enable_cpuslocked(struct static_key *key); extern void static_key_disable_cpuslocked(struct static_key *key); extern enum jump_label_type jump_label_init_type(struct jump_entry *entry); +#ifdef CONFIG_LIVEPATCH_WO_FTRACE +extern int jump_label_register(struct module *mod); +#endif
/* * We should be using ATOMIC_INIT() for initializing .enabled, but @@ -314,6 +317,13 @@ static inline int jump_label_text_reserved(void *start, void *end) static inline void jump_label_lock(void) {} static inline void jump_label_unlock(void) {}
+#ifdef CONFIG_LIVEPATCH_WO_FTRACE +static inline int jump_label_register(struct module *mod) +{ + return 0; +} +#endif + static inline void static_key_enable(struct static_key *key) { STATIC_KEY_CHECK_USE(key); diff --git a/include/linux/module.h b/include/linux/module.h index a98e188cf37b..c6ee29331e87 100644 --- a/include/linux/module.h +++ b/include/linux/module.h @@ -383,6 +383,12 @@ struct mod_kallsyms { };
#ifdef CONFIG_LIVEPATCH +enum MODULE_KLP_REL_STATE { + MODULE_KLP_REL_NONE = 0, + MODULE_KLP_REL_UNDO, + MODULE_KLP_REL_DONE, +}; + /** * struct klp_modinfo - ELF information preserved from the livepatch module * @@ -551,6 +557,19 @@ struct module {
/* ELF information */ struct klp_modinfo *klp_info; + /* + * livepatch should relocate the key of jump_label by + * using klp_apply_section_relocs. So it's necessary to + * do jump_label_apply_nops() and jump_label_add_module() + * later after livepatch relocation finised. + * + * for normal module : + * always MODULE_KLP_REL_DONE. + * for livepatch module : + * init as MODULE_KLP_REL_UNDO, + * set to MODULE_KLP_REL_DONE when relocate completed. + */ + enum MODULE_KLP_REL_STATE klp_rel_state; /* Only used in the solution without ftrace */ #endif
#ifdef CONFIG_PRINTK_INDEX @@ -750,6 +769,20 @@ static inline bool is_livepatch_module(struct module *mod) #endif }
+#ifdef CONFIG_LIVEPATCH_WO_FTRACE +static inline void set_mod_klp_rel_state(struct module *mod, + enum MODULE_KLP_REL_STATE state) +{ + mod->klp_rel_state = state; +} + +static inline bool mod_klp_rel_completed(struct module *mod) +{ + return mod->klp_rel_state == MODULE_KLP_REL_NONE || + mod->klp_rel_state == MODULE_KLP_REL_DONE; +} +#endif /* CONFIG_LIVEPATCH_WO_FTRACE */ + void set_module_sig_enforced(void);
#else /* !CONFIG_MODULES... */ diff --git a/kernel/jump_label.c b/kernel/jump_label.c index d9c822bbffb8..97c06f095358 100644 --- a/kernel/jump_label.c +++ b/kernel/jump_label.c @@ -628,6 +628,11 @@ static int jump_label_add_module(struct module *mod) struct static_key *key = NULL; struct static_key_mod *jlm, *jlm2;
+#ifdef CONFIG_LIVEPATCH_WO_FTRACE + if (unlikely(!mod_klp_rel_completed(mod))) + return 0; +#endif + /* if the module doesn't have jump label entries, just return */ if (iter_start == iter_stop) return 0; @@ -690,6 +695,11 @@ static void jump_label_del_module(struct module *mod) struct static_key *key = NULL; struct static_key_mod *jlm, **prev;
+#ifdef CONFIG_LIVEPATCH_WO_FTRACE + if (unlikely(!mod_klp_rel_completed(mod))) + return; +#endif + for (iter = iter_start; iter < iter_stop; iter++) { if (jump_entry_key(iter) == key) continue; @@ -766,6 +776,18 @@ static struct notifier_block jump_label_module_nb = { .priority = 1, /* higher than tracepoints */ };
+#ifdef CONFIG_LIVEPATCH_WO_FTRACE +int jump_label_register(struct module *mod) +{ + int ret; + + ret = jump_label_module_notify(&jump_label_module_nb, + MODULE_STATE_COMING, mod); + + return notifier_to_errno(ret); +} +#endif /* CONFIG_LIVEPATCH_WO_FTRACE */ + static __init int jump_label_init_module(void) { return register_module_notifier(&jump_label_module_nb); diff --git a/kernel/livepatch/core.c b/kernel/livepatch/core.c index 1d30eb906def..73a5a3c09d3e 100644 --- a/kernel/livepatch/core.c +++ b/kernel/livepatch/core.c @@ -1061,6 +1061,12 @@ static int klp_init_patch(struct klp_patch *patch) }
#ifdef CONFIG_LIVEPATCH_WO_FTRACE + set_mod_klp_rel_state(patch->mod, MODULE_KLP_REL_DONE); + ret = jump_label_register(patch->mod); + if (ret) { + pr_err("register jump label failed, ret=%d\n", ret); + return ret; + } klp_for_each_object(patch, obj) klp_load_hook(obj); #endif diff --git a/kernel/module/main.c b/kernel/module/main.c index 98fedfdb8db5..d5765c6cd188 100644 --- a/kernel/module/main.c +++ b/kernel/module/main.c @@ -1918,9 +1918,17 @@ static int copy_chunked_from_user(void *dst, const void __user *usrc, unsigned l
static int check_modinfo_livepatch(struct module *mod, struct load_info *info) { +#ifdef CONFIG_LIVEPATCH_WO_FTRACE + if (!get_modinfo(info, "livepatch")) { + set_mod_klp_rel_state(mod, MODULE_KLP_REL_NONE); + return 0; + } + set_mod_klp_rel_state(mod, MODULE_KLP_REL_UNDO); +#else /* !CONFIG_LIVEPATCH_WO_FTRACE */ if (!get_modinfo(info, "livepatch")) /* Nothing more to do */ return 0; +#endif /* CONFIG_LIVEPATCH_WO_FTRACE */
if (set_livepatch_module(mod)) return 0;