Commit 315bed18 authored by Zheng Yejian's avatar Zheng Yejian
Browse files

livepatch/core: Support jump_label

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


CVE: NA

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

The kpatch-build processes the __jump_table special section,
and only the jump_lable used by the changed functions will be
included in __jump_table section, and the livepatch should
process the tracepoint again after the dynamic relocation.

NOTE: adding new tracepoints definition is not supported.

Signed-off-by: default avatarCheng Jian <cj.chengjian@huawei.com>
Signed-off-by: default avatarWang ShaoBo <bobo.shaobowang@huawei.com>
Signed-off-by: default avatarDong Kai <dongkai11@huawei.com>
Signed-off-by: default avatarYe Weihua <yeweihua4@huawei.com>
Signed-off-by: default avatarZheng Yejian <zhengyejian1@huawei.com>
parent c001741b
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -235,6 +235,9 @@ extern void static_key_disable(struct static_key *key);
extern void static_key_enable_cpuslocked(struct static_key *key);
extern void static_key_disable_cpuslocked(struct static_key *key);
extern enum jump_label_type jump_label_init_type(struct jump_entry *entry);
#ifdef CONFIG_LIVEPATCH_WO_FTRACE
extern int jump_label_register(struct module *mod);
#endif

/*
 * We should be using ATOMIC_INIT() for initializing .enabled, but
@@ -314,6 +317,13 @@ static inline int jump_label_text_reserved(void *start, void *end)
static inline void jump_label_lock(void) {}
static inline void jump_label_unlock(void) {}

#ifdef CONFIG_LIVEPATCH_WO_FTRACE
static inline int jump_label_register(struct module *mod)
{
	return 0;
}
#endif

static inline void static_key_enable(struct static_key *key)
{
	STATIC_KEY_CHECK_USE(key);
+33 −0
Original line number Diff line number Diff line
@@ -383,6 +383,12 @@ struct mod_kallsyms {
};

#ifdef CONFIG_LIVEPATCH
enum MODULE_KLP_REL_STATE {
	MODULE_KLP_REL_NONE = 0,
	MODULE_KLP_REL_UNDO,
	MODULE_KLP_REL_DONE,
};

/**
 * struct klp_modinfo - ELF information preserved from the livepatch module
 *
@@ -551,6 +557,19 @@ struct module {

	/* ELF information */
	struct klp_modinfo *klp_info;
	/*
	 * livepatch should relocate the key of jump_label by
	 * using klp_apply_section_relocs. So it's necessary to
	 * do jump_label_apply_nops() and jump_label_add_module()
	 * later after livepatch relocation finised.
	 *
	 * for normal module :
	 *	always MODULE_KLP_REL_DONE.
	 * for livepatch module :
	 *	init as MODULE_KLP_REL_UNDO,
	 *	set to MODULE_KLP_REL_DONE when relocate completed.
	 */
	enum MODULE_KLP_REL_STATE klp_rel_state; /* Only used in the solution without ftrace */
#endif

#ifdef CONFIG_PRINTK_INDEX
@@ -750,6 +769,20 @@ static inline bool is_livepatch_module(struct module *mod)
#endif
}

#ifdef CONFIG_LIVEPATCH_WO_FTRACE
static inline void set_mod_klp_rel_state(struct module *mod,
			enum MODULE_KLP_REL_STATE state)
{
	mod->klp_rel_state = state;
}

static inline bool mod_klp_rel_completed(struct module *mod)
{
	return mod->klp_rel_state == MODULE_KLP_REL_NONE ||
		mod->klp_rel_state == MODULE_KLP_REL_DONE;
}
#endif /* CONFIG_LIVEPATCH_WO_FTRACE */

void set_module_sig_enforced(void);

#else /* !CONFIG_MODULES... */
+22 −0
Original line number Diff line number Diff line
@@ -628,6 +628,11 @@ static int jump_label_add_module(struct module *mod)
	struct static_key *key = NULL;
	struct static_key_mod *jlm, *jlm2;

#ifdef CONFIG_LIVEPATCH_WO_FTRACE
	if (unlikely(!mod_klp_rel_completed(mod)))
		return 0;
#endif

	/* if the module doesn't have jump label entries, just return */
	if (iter_start == iter_stop)
		return 0;
@@ -690,6 +695,11 @@ static void jump_label_del_module(struct module *mod)
	struct static_key *key = NULL;
	struct static_key_mod *jlm, **prev;

#ifdef CONFIG_LIVEPATCH_WO_FTRACE
	if (unlikely(!mod_klp_rel_completed(mod)))
		return;
#endif

	for (iter = iter_start; iter < iter_stop; iter++) {
		if (jump_entry_key(iter) == key)
			continue;
@@ -766,6 +776,18 @@ static struct notifier_block jump_label_module_nb = {
	.priority = 1, /* higher than tracepoints */
};

#ifdef CONFIG_LIVEPATCH_WO_FTRACE
int jump_label_register(struct module *mod)
{
	int ret;

	ret = jump_label_module_notify(&jump_label_module_nb,
			MODULE_STATE_COMING, mod);

	return notifier_to_errno(ret);
}
#endif /* CONFIG_LIVEPATCH_WO_FTRACE */

static __init int jump_label_init_module(void)
{
	return register_module_notifier(&jump_label_module_nb);
+6 −0
Original line number Diff line number Diff line
@@ -1060,6 +1060,12 @@ static int klp_init_patch(struct klp_patch *patch)
	}

#ifdef CONFIG_LIVEPATCH_WO_FTRACE
	set_mod_klp_rel_state(patch->mod, MODULE_KLP_REL_DONE);
	ret = jump_label_register(patch->mod);
	if (ret) {
		pr_err("register jump label failed, ret=%d\n", ret);
		return ret;
	}
	klp_for_each_object(patch, obj)
		klp_load_hook(obj);
#endif
+8 −0
Original line number Diff line number Diff line
@@ -1918,9 +1918,17 @@ static int copy_chunked_from_user(void *dst, const void __user *usrc, unsigned l

static int check_modinfo_livepatch(struct module *mod, struct load_info *info)
{
#ifdef CONFIG_LIVEPATCH_WO_FTRACE
	if (!get_modinfo(info, "livepatch")) {
		set_mod_klp_rel_state(mod, MODULE_KLP_REL_NONE);
		return 0;
	}
	set_mod_klp_rel_state(mod, MODULE_KLP_REL_UNDO);
#else /* !CONFIG_LIVEPATCH_WO_FTRACE */
	if (!get_modinfo(info, "livepatch"))
		/* Nothing more to do */
		return 0;
#endif /* CONFIG_LIVEPATCH_WO_FTRACE */

	if (set_livepatch_module(mod))
		return 0;