Commit 1f8a38ca authored by Zheng Yejian's avatar Zheng Yejian Committed by Zheng Zengkai
Browse files

livepatch: Fix patching functions which have static_call

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: default avatarZheng Yejian <zhengyejian1@huawei.com>
Reviewed-by: default avatarKuohai Xu <xukuohai@huawei.com>
Signed-off-by: default avatarZheng Zengkai <zhengzengkai@huawei.com>
parent 494188df
Loading
Loading
Loading
Loading
+19 −0
Original line number Diff line number Diff line
@@ -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
+19 −0
Original line number Diff line number Diff line
@@ -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;