Commit 2c3c0b3a authored by Zheng Yejian's avatar Zheng Yejian Committed by Zheng Zengkai
Browse files

livepatch/x86: Avoid conflict with static {call,key}

hulk inclusion
category: bugfix
bugzilla: https://gitee.com/openeuler/kernel/issues/I60L10


CVE: NA

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

static call and static key allow user to modify instructions on call
site, relate configs are: CONFIG_HAVE_STATIC_CALL_INLINE for static
call, CONFIG_JUMP_LABEL for static key.

When they exist in first several instruction of an old function, and
livepatch could also modify there, then confliction happened.

To avoid the confliction, we don't allow a livepatch module of this case
to be inserted.

Fixes: c33e4283 ("livepatch/core: Allow implementation without ftrace")
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 ed8c4c72
Loading
Loading
Loading
Loading
+42 −0
Original line number Diff line number Diff line
@@ -34,6 +34,7 @@
#include <linux/delay.h>
#include <linux/stop_machine.h>
#endif
#include <linux/static_call.h>

/*
 * klp_mutex is a coarse lock which serializes access to klp data.  All
@@ -1195,6 +1196,43 @@ extern int klp_static_call_register(struct module *mod);
static inline int klp_static_call_register(struct module *mod) { return 0; }
#endif

static int check_address_conflict(struct klp_patch *patch)
{
	struct klp_object *obj;
	struct klp_func *func;
	int ret;
	void *start;
	void *end;

	/*
	 * Locks seem required as comment of jump_label_text_reserved() said:
	 *   Caller must hold jump_label_mutex.
	 * But looking into implementation of jump_label_text_reserved() and
	 * static_call_text_reserved(), call sites of every jump_label or static_call
	 * are checked, and they won't be changed after corresponding module inserted,
	 * so no need to take jump_label_lock and static_call_lock here.
	 */
	klp_for_each_object(patch, obj) {
		klp_for_each_func(obj, func) {
			start = func->old_func;
			end = start + KLP_MAX_REPLACE_SIZE - 1;
			ret = jump_label_text_reserved(start, end);
			if (ret) {
				pr_err("'%s' has static key in first %zu bytes, ret=%d\n",
				       func->old_name, KLP_MAX_REPLACE_SIZE, ret);
				return -EINVAL;
			}
			ret = static_call_text_reserved(start, end);
			if (ret) {
				pr_err("'%s' has static call in first %zu bytes, ret=%d\n",
				       func->old_name, KLP_MAX_REPLACE_SIZE, ret);
				return -EINVAL;
			}
		}
	}
	return 0;
}

static int klp_init_patch(struct klp_patch *patch)
{
	struct klp_object *obj;
@@ -1241,6 +1279,10 @@ static int klp_init_patch(struct klp_patch *patch)
	}
	module_enable_ro(patch->mod, true);

	ret = check_address_conflict(patch);
	if (ret)
		return ret;

#ifdef CONFIG_LIVEPATCH_STOP_MACHINE_CONSISTENCY
	klp_for_each_object(patch, obj)
		klp_load_hook(obj);