Commit 003c04ed authored by Yang Jihong's avatar Yang Jihong Committed by Zheng Zengkai
Browse files

livepatch: Add klp_module_delete_safety_check

hulk inclusion
category: feature
bugzilla: https://gitee.com/openeuler/kernel/issues/I5CJ7X



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

Add klp_module_delete_safety_check for calltrace check during module
deletion to avoid unsafe resource release.

Signed-off-by: default avatarYang Jihong <yangjihong1@huawei.com>
Reviewed-by: default avatarXu Kuohai <xukuohai@huawei.com>
Signed-off-by: default avatarZheng Zengkai <zhengzengkai@huawei.com>
parent 4b69775b
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -257,6 +257,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);

#endif

+36 −0
Original line number Diff line number Diff line
@@ -1426,6 +1426,11 @@ 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;
}

static struct klp_func_node *func_node_alloc(struct klp_func *func)
{
	long ret;
@@ -2093,6 +2098,37 @@ int klp_unregister_patch(struct klp_patch *patch)
}
EXPORT_SYMBOL_GPL(klp_unregister_patch);

/**
 * 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;
}

#endif /* #ifdef CONFIG_LIVEPATCH_STOP_MACHINE_CONSISTENCY */
/*
 * This function unpatches objects from the replaced livepatches.
+9 −0
Original line number Diff line number Diff line
@@ -57,6 +57,9 @@
#include <linux/bsearch.h>
#include <linux/dynamic_debug.h>
#include <linux/audit.h>
#ifdef CONFIG_LIVEPATCH_STOP_MACHINE_CONSISTENCY
#include <linux/livepatch.h>
#endif
#include <uapi/linux/module.h>
#include "module-internal.h"

@@ -1027,6 +1030,12 @@ SYSCALL_DEFINE2(delete_module, const char __user *, name_user,
		}
	}

#ifdef CONFIG_LIVEPATCH_STOP_MACHINE_CONSISTENCY
	ret = klp_module_delete_safety_check(mod);
	if (ret != 0)
		goto out;
#endif

	/* Stop the machine so refcounts can't move and disable module. */
	ret = try_stop_module(mod, flags, &forced);
	if (ret != 0)