From: Zheng Yejian zhengyejian1@huawei.com
hulk inclusion category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I60L10 CVE: NA
--------------------------------
It was reported that if 'static_call' is used in a old function, then the livepatch module created by kpatch for that old function cannot be inserted normally.
Root cause is that relocation of static_call symbols in livepatch module has not been done while initing: load_module prepare_coming_module blocking_notifier_call_chain_robust notifier_call_chain_robust static_call_module_notify <-- 1. static_call symbols init here, but relocation is done at below MARK "2." do_init_module do_one_initcall klp_register_patch klp_init_patch klp_init_object klp_init_object_loaded <-- 2. relocate .klp.xxx here
To solve it, we move the static_call initialization after relocation.
Signed-off-by: Zheng Yejian zhengyejian1@huawei.com Reviewed-by: Kuohai Xu xukuohai@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- kernel/livepatch/core.c | 19 +++++++++++++++++++ kernel/static_call.c | 19 +++++++++++++++++++ 2 files changed, 38 insertions(+)
diff --git a/kernel/livepatch/core.c b/kernel/livepatch/core.c index f6981faa18a8..338c2624de0e 100644 --- a/kernel/livepatch/core.c +++ b/kernel/livepatch/core.c @@ -1192,6 +1192,12 @@ static void klp_init_patch_early(struct klp_patch *patch) } }
+#if defined(CONFIG_HAVE_STATIC_CALL_INLINE) +extern int klp_static_call_register(struct module *mod); +#else +static inline int klp_static_call_register(struct module *mod) { return 0; } +#endif + static int klp_init_patch(struct klp_patch *patch) { struct klp_object *obj; @@ -1223,6 +1229,19 @@ static int klp_init_patch(struct klp_patch *patch) pr_err("register jump label failed, ret=%d\n", ret); return ret; } + ret = klp_static_call_register(patch->mod); + if (ret) { + /* + * We no need to distinctly clean pre-registered jump_label + * here because it will be clean at path: + * load_module + * do_init_module + * fail_free_freeinit: <-- notify GOING here + */ + module_enable_ro(patch->mod, true); + pr_err("register static call failed, ret=%d\n", ret); + return ret; + } module_enable_ro(patch->mod, true);
#ifdef CONFIG_LIVEPATCH_STOP_MACHINE_CONSISTENCY diff --git a/kernel/static_call.c b/kernel/static_call.c index 43ba0b1e0edb..d38f6a92e3e4 100644 --- a/kernel/static_call.c +++ b/kernel/static_call.c @@ -356,6 +356,9 @@ static int static_call_add_module(struct module *mod) struct static_call_site *stop = start + mod->num_static_call_sites; struct static_call_site *site;
+ if (unlikely(!mod_klp_rel_completed(mod))) + return 0; + for (site = start; site != stop; site++) { unsigned long s_key = __static_call_key(site); unsigned long addr = s_key & ~STATIC_CALL_SITE_FLAGS; @@ -398,6 +401,9 @@ static void static_call_del_module(struct module *mod) struct static_call_mod *site_mod, **prev; struct static_call_site *site;
+ if (unlikely(!mod_klp_rel_completed(mod))) + return; + for (site = start; site < stop; site++) { key = static_call_key(site); if (key == prev_key) @@ -450,8 +456,21 @@ static struct notifier_block static_call_module_nb = { .notifier_call = static_call_module_notify, };
+int klp_static_call_register(struct module *mod) +{ + int ret; + + ret = static_call_module_notify(&static_call_module_nb, MODULE_STATE_COMING, mod); + return notifier_to_errno(ret); +} + #else
+int klp_static_call_register(struct module *mod) +{ + return 0; +} + static inline int __static_call_mod_text_reserved(void *start, void *end) { return 0;