提交 2220964a 编写于 作者: D David Vernet 提交者: Zheng Zengkai

livepatch: Fix kobject refcount bug on klp_init_patch_early failure path

mainline inclusion
from mainline-v5.17-rc1
commit 5ef3dd20
category: bugfix
bugzilla: https://gitee.com/openeuler/kernel/issues/I4TF7T
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=5ef3dd20555e8e878ac390a71e658db5fd02845c

--------------------------------

When enabling a klp patch with klp_enable_patch(), klp_init_patch_early()
is invoked to initialize the kobjects for the patch itself, as well as the
'struct klp_object' and 'struct klp_func' objects that comprise it.
However, there are some error paths in klp_enable_patch() where some
kobjects may have been initialized with kobject_init(), but an error code
is still returned due to e.g. a 'struct klp_object' having a NULL funcs
pointer.

In these paths, the initial reference of the kobject of the 'struct
klp_patch' may never be released, along with one or more of its objects and
their functions, as kobject_put() is not invoked on the cleanup path if
klp_init_patch_early() returns an error code.

For example, if an object entry such as the following were added to the
sample livepatch module's klp patch, it would cause the vmlinux klp_object,
and its klp_func which updates 'cmdline_proc_show', to never be released:

static struct klp_object objs[] = {
	{
		/* name being NULL means vmlinux */
		.funcs = funcs,
	},
	{
		/* NULL funcs -- would cause reference leak */
		.name = "kvm",
	}, { }
};

Without this change, if CONFIG_DEBUG_KOBJECT is enabled, and the sample klp
patch is loaded, the kobjects (the patch, the vmlinux 'struct klp_object',
and its func) are observed as initialized, but never released, in the dmesg
log output.  With the change, these kobject references no longer fail to be
released as the error case is properly handled before they are initialized.

Since 81fd525cedd9 ("[Huawei] livepatch: Add klp_{register,unregister}_patch
for stop_machine model"), klp_register_patch was born out of klp_enable_patch
with similar issue, we also fix it in this patch.
Signed-off-by: NDavid Vernet <void@manifault.com>
Reviewed-by: NPetr Mladek <pmladek@suse.com>
Acked-by: NMiroslav Benes <mbenes@suse.cz>
Acked-by: NJosh Poimboeuf <jpoimboe@redhat.com>
Signed-off-by: NPetr Mladek <pmladek@suse.com>

Conflicts:
	kernel/livepatch/core.c

Fixes: 0430f78b ("livepatch: Consolidate klp_free functions")
Fixes: c33e4283 ("livepatch/core: Allow implementation without ftrace")
Signed-off-by: NZheng Yejian <zhengyejian1@huawei.com>
Signed-off-by: NZheng Zengkai <zhengzengkai@huawei.com>
上级 85719919
...@@ -1146,14 +1146,11 @@ static void klp_init_object_early(struct klp_patch *patch, ...@@ -1146,14 +1146,11 @@ static void klp_init_object_early(struct klp_patch *patch,
#endif #endif
} }
static int klp_init_patch_early(struct klp_patch *patch) static void klp_init_patch_early(struct klp_patch *patch)
{ {
struct klp_object *obj; struct klp_object *obj;
struct klp_func *func; struct klp_func *func;
if (!patch->objs)
return -EINVAL;
INIT_LIST_HEAD(&patch->list); INIT_LIST_HEAD(&patch->list);
INIT_LIST_HEAD(&patch->obj_list); INIT_LIST_HEAD(&patch->obj_list);
kobject_init(&patch->kobj, &klp_ktype_patch); kobject_init(&patch->kobj, &klp_ktype_patch);
...@@ -1163,26 +1160,12 @@ static int klp_init_patch_early(struct klp_patch *patch) ...@@ -1163,26 +1160,12 @@ static int klp_init_patch_early(struct klp_patch *patch)
init_completion(&patch->finish); init_completion(&patch->finish);
klp_for_each_object_static(patch, obj) { klp_for_each_object_static(patch, obj) {
if (!obj->funcs)
return -EINVAL;
klp_init_object_early(patch, obj); klp_init_object_early(patch, obj);
klp_for_each_func_static(obj, func) { klp_for_each_func_static(obj, func) {
klp_init_func_early(obj, func); klp_init_func_early(obj, func);
} }
} }
/*
* For stop_machine model, we only need to module_get and module_put once when
* enable_patch and disable_patch respectively.
*/
#ifdef CONFIG_LIVEPATCH_PER_TASK_CONSISTENCY
if (!try_module_get(patch->mod))
return -ENODEV;
#endif
return 0;
} }
static int klp_init_patch(struct klp_patch *patch) static int klp_init_patch(struct klp_patch *patch)
...@@ -1431,10 +1414,16 @@ static int __klp_enable_patch(struct klp_patch *patch) ...@@ -1431,10 +1414,16 @@ static int __klp_enable_patch(struct klp_patch *patch)
int klp_enable_patch(struct klp_patch *patch) int klp_enable_patch(struct klp_patch *patch)
{ {
int ret; int ret;
struct klp_object *obj;
if (!patch || !patch->mod) if (!patch || !patch->mod || !patch->objs)
return -EINVAL; return -EINVAL;
klp_for_each_object_static(patch, obj) {
if (!obj->funcs)
return -EINVAL;
}
if (!is_livepatch_module(patch->mod)) { if (!is_livepatch_module(patch->mod)) {
pr_err("module %s is not marked as a livepatch module\n", pr_err("module %s is not marked as a livepatch module\n",
patch->mod->name); patch->mod->name);
...@@ -1458,11 +1447,10 @@ int klp_enable_patch(struct klp_patch *patch) ...@@ -1458,11 +1447,10 @@ int klp_enable_patch(struct klp_patch *patch)
return -EINVAL; return -EINVAL;
} }
ret = klp_init_patch_early(patch); if (!try_module_get(patch->mod))
if (ret) { return -ENODEV;
mutex_unlock(&klp_mutex);
return ret; klp_init_patch_early(patch);
}
ret = klp_init_patch(patch); ret = klp_init_patch(patch);
if (ret) if (ret)
...@@ -1609,10 +1597,16 @@ static int __klp_enable_patch(struct klp_patch *patch) ...@@ -1609,10 +1597,16 @@ static int __klp_enable_patch(struct klp_patch *patch)
int klp_register_patch(struct klp_patch *patch) int klp_register_patch(struct klp_patch *patch)
{ {
int ret; int ret;
struct klp_object *obj;
if (!patch || !patch->mod) if (!patch || !patch->mod || !patch->objs)
return -EINVAL; return -EINVAL;
klp_for_each_object_static(patch, obj) {
if (!obj->funcs)
return -EINVAL;
}
if (!is_livepatch_module(patch->mod)) { if (!is_livepatch_module(patch->mod)) {
pr_err("module %s is not marked as a livepatch module\n", pr_err("module %s is not marked as a livepatch module\n",
patch->mod->name); patch->mod->name);
...@@ -1629,11 +1623,7 @@ int klp_register_patch(struct klp_patch *patch) ...@@ -1629,11 +1623,7 @@ int klp_register_patch(struct klp_patch *patch)
return -EINVAL; return -EINVAL;
} }
ret = klp_init_patch_early(patch); klp_init_patch_early(patch);
if (ret) {
mutex_unlock(&klp_mutex);
return ret;
}
ret = klp_init_patch(patch); ret = klp_init_patch(patch);
if (ret) if (ret)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册