hulk inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I8MGE6
--------------------------------
Add klp_module_delete_safety_check for calltrace check during module deletion to avoid unsafe resource release.
Signed-off-by: Yang Jihong yangjihong1@huawei.com Signed-off-by: Zheng Yejian zhengyejian1@huawei.com --- include/linux/livepatch.h | 1 + kernel/livepatch/core.c | 36 ++++++++++++++++++++++++++++++++++++ kernel/module/main.c | 6 ++++++ 3 files changed, 43 insertions(+)
diff --git a/include/linux/livepatch.h b/include/linux/livepatch.h index e6d9a794ad77..3388a611f388 100644 --- a/include/linux/livepatch.h +++ b/include/linux/livepatch.h @@ -283,6 +283,7 @@ int klp_compare_address(unsigned long pc, unsigned long func_addr, }
void arch_klp_init(void); +int klp_module_delete_safety_check(struct module *mod);
typedef int (*klp_add_func_t)(struct list_head *func_list, unsigned long func_addr, unsigned long func_size, diff --git a/kernel/livepatch/core.c b/kernel/livepatch/core.c index 35a016c83ae2..2abf8db039d0 100644 --- a/kernel/livepatch/core.c +++ b/kernel/livepatch/core.c @@ -2026,6 +2026,42 @@ void __weak arch_klp_set_brk_func(struct klp_func_node *func_node, void *new_fun func_node->brk_func = new_func; }
+int __weak arch_klp_module_check_calltrace(void *data) +{ + return 0; +} + +/** + * klp_module_delete_safety_check() - safety check in livepatch scenario when delete a module + * @mod: Module to be deleted + * + * Module refcnt ensures that there is no rare case between enable_patch and delete_module: + * 1. safety_check -> try_enable_patch -> try_release_module_ref: + * try_enable_patch would increase module refcnt, which cause try_release_module_ref fails. + * 2. safety_check -> try_release_module_ref -> try_enable_patch: + * after release module ref, try_enable_patch would fail because try_module_get fails. + * So the problem that release resources unsafely when enable livepatch after safety_check is + * passed during module deletion does not exist, complex synchronization protection is not + * required. + + * Return: 0 on success, otherwise error + */ +int klp_module_delete_safety_check(struct module *mod) +{ + int ret; + + if (!mod || !is_livepatch_module(mod)) + return 0; + + ret = stop_machine(arch_klp_module_check_calltrace, (void *)mod, NULL); + if (ret) { + pr_debug("failed to check klp module calltrace: %d\n", ret); + return ret; + } + + return 0; +} + static struct klp_func_node *func_node_alloc(struct klp_func *func) { long ret; diff --git a/kernel/module/main.c b/kernel/module/main.c index 4f1592035229..a59a6868f170 100644 --- a/kernel/module/main.c +++ b/kernel/module/main.c @@ -745,6 +745,12 @@ SYSCALL_DEFINE2(delete_module, const char __user *, name_user, } }
+#ifdef CONFIG_LIVEPATCH_WO_FTRACE + ret = klp_module_delete_safety_check(mod); + if (ret != 0) + goto out; +#endif + ret = try_stop_module(mod, flags, &forced); if (ret != 0) goto out;