Commit 6b65db0b authored by Zheng Yejian's avatar Zheng Yejian
Browse files

livepatch: Fix huge_depth in arch_klp_check_activeness_func()

hulk inclusion
category: cleanup
bugzilla: https://gitee.com/openeuler/kernel/issues/I9R2TB



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

Fix cmetrics warning like below:
  cmetrics-the depth of the method {arch_klp_check_activeness_func()}
  is 6, it is over 4

At the same time, arch_klp_check_activeness_func() in x86/arm/arm64/ppc32
are almost the same, so move it out of arch and reduce duplicate codes.

Signed-off-by: default avatarZheng Yejian <zhengyejian1@huawei.com>
parent 3deefe81
Loading
Loading
Loading
Loading
+1 −122
Original line number Diff line number Diff line
@@ -69,7 +69,7 @@ struct walk_stackframe_args {
	bool (*check_func)(void *data, int *ret, unsigned long pc);
};

static bool check_jump_insn(unsigned long func_addr)
bool arch_check_jump_insn(unsigned long func_addr)
{
	unsigned long i;
	u32 *insn = (u32*)func_addr;
@@ -83,127 +83,6 @@ static bool check_jump_insn(unsigned long func_addr)
	return false;
}

int arch_klp_check_activeness_func(struct klp_patch *patch, int enable,
				   klp_add_func_t add_func, struct list_head *func_list)
{
	int ret;
	struct klp_object *obj;
	struct klp_func_node *func_node;
	struct klp_func *func;
	unsigned long func_addr = 0;
	unsigned long func_size;

	for (obj = patch->objs; obj->funcs; obj++) {
		for (func = obj->funcs; func->old_name; func++) {
			unsigned long old_func = (unsigned long)func->old_func;

			if (enable) {
				bool need_check_old = false;

				if (func->patched || func->force == KLP_ENFORCEMENT)
					continue;
				/*
				 * When enable, checking the currently
				 * active functions.
				 */
				func_node = klp_find_func_node(func->old_func);
				if (!func_node ||
				    list_empty(&func_node->func_stack)) {
					/*
					 * No patched on this function
					 * [ the origin one ]
					 */
					func_addr = old_func;
					func_size = func->old_size;
				} else {
					/*
					 * Previously patched function
					 * [ the active one ]
					 */
					struct klp_func *prev;

					prev = list_first_or_null_rcu(
						&func_node->func_stack,
						struct klp_func, stack_node);
					func_addr = (unsigned long)prev->new_func;
					func_size = prev->new_size;
				}
				/*
				 * When preemption is disabled and the
				 * replacement area does not contain a jump
				 * instruction, the migration thread is
				 * scheduled to run stop machine only after the
				 * excution of intructions to be replaced is
				 * complete.
				 */
				if (IS_ENABLED(CONFIG_PREEMPTION) ||
				    IS_ENABLED(CONFIG_LIVEPATCH_BREAKPOINT_NO_STOP_MACHINE) ||
				    (func->force == KLP_NORMAL_FORCE) ||
				    check_jump_insn(func_addr)) {
					ret = add_func(func_list, func_addr, func_size,
							func->old_name, func->force);
					if (ret)
						return ret;
					need_check_old = (func_addr != old_func);
				}
				if (need_check_old) {
					ret = add_func_to_list(check_funcs, &pcheck, old_func,
						func->old_size, func->old_name, func->force);
					if (ret)
						return ret;
				}
			} else {
				/*
				 * When disable, check for the previously
				 * patched function and the function itself
				 * which to be unpatched.
				 */
				func_node = klp_find_func_node(func->old_func);
				if (!func_node)
					return -EINVAL;
#ifdef CONFIG_PREEMPTION
				/*
				 * No scheduling point in the replacement
				 * instructions. Therefore, when preemption is
				 * not enabled, atomic execution is performed
				 * and these instructions will not appear on
				 * the stack.
				 */
				if (list_is_singular(&func_node->func_stack)) {
					func_addr = old_func;
					func_size = func->old_size;
				} else {
					struct klp_func *prev;

					prev = list_first_or_null_rcu(
						&func_node->func_stack,
						struct klp_func, stack_node);
					func_addr = (unsigned long)prev->new_func;
					func_size = prev->new_size;
				}
				ret = add_func(func_list, func_addr, func_size,
						func->old_name, 0);
				if (ret)
					return ret;
				if (func_addr != old_func) {
					ret = add_func_to_list(check_funcs, &pcheck, old_func,
						func->old_size, func->old_name, 0);
					if (ret)
						return ret;
				}
#endif
				func_addr = (unsigned long)func->new_func;
				func_size = func->new_size;
				ret = add_func(func_list, func_addr, func_size,
						func->old_name, 0);
				if (ret)
					return ret;
			}
		}
	}
	return 0;
}

static int klp_check_jump_func(struct stackframe *frame, void *ws_args)
{
	struct walk_stackframe_args *args = ws_args;
+1 −120
Original line number Diff line number Diff line
@@ -62,7 +62,7 @@ struct walk_stackframe_args {
	bool (*check_func)(void *data, int *ret, unsigned long pc);
};

static bool check_jump_insn(unsigned long func_addr)
bool arch_check_jump_insn(unsigned long func_addr)
{
	unsigned long i;
	u32 *insn = (u32*)func_addr;
@@ -76,125 +76,6 @@ static bool check_jump_insn(unsigned long func_addr)
	return false;
}

int arch_klp_check_activeness_func(struct klp_patch *patch, int enable,
				   klp_add_func_t add_func, struct list_head *func_list)
{
	int ret;
	struct klp_object *obj;
	struct klp_func *func;
	unsigned long func_addr = 0;
	unsigned long func_size;
	struct klp_func_node *func_node;

	for (obj = patch->objs; obj->funcs; obj++) {
		for (func = obj->funcs; func->old_name; func++) {
			unsigned long old_func = (unsigned long)func->old_func;

			if (enable) {
				bool need_check_old = false;

				if (func->patched || func->force == KLP_ENFORCEMENT)
					continue;
				/*
				 * When enable, checking the currently
				 * active functions.
				 */
				func_node = klp_find_func_node(func->old_func);
				if (!func_node ||
				    list_empty(&func_node->func_stack)) {
					func_addr = old_func;
					func_size = func->old_size;
				} else {
					/*
					 * Previously patched function
					 * [the active one]
					 */
					struct klp_func *prev;

					prev = list_first_or_null_rcu(
						&func_node->func_stack,
						struct klp_func, stack_node);
					func_addr = (unsigned long)prev->new_func;
					func_size = prev->new_size;
				}
				/*
				 * When preemption is disabled and the
				 * replacement area does not contain a jump
				 * instruction, the migration thread is
				 * scheduled to run stop machine only after the
				 * excution of instructions to be replaced is
				 * complete.
				 */
				if (IS_ENABLED(CONFIG_PREEMPTION) ||
				    IS_ENABLED(CONFIG_LIVEPATCH_BREAKPOINT_NO_STOP_MACHINE) ||
				    (func->force == KLP_NORMAL_FORCE) ||
				    check_jump_insn(func_addr)) {
					ret = add_func(func_list, func_addr, func_size,
							func->old_name, func->force);
					if (ret)
						return ret;
					need_check_old = (func_addr != old_func);
				}
				if (need_check_old) {
					ret = add_func_to_list(check_funcs, &pcheck, old_func,
						func->old_size, func->old_name, func->force);
					if (ret)
						return ret;
				}
			} else {
				/*
				 * When disable, check for the previously
				 * patched function and the function itself
				 * which to be unpatched.
				 */
				func_node = klp_find_func_node(func->old_func);
				if (!func_node) {
					return -EINVAL;
				}
#ifdef CONFIG_PREEMPTION
				/*
				 * No scheduling point in the replacement
				 * instructions. Therefore, when preemption is
				 * not enabled, atomic execution is performed
				 * and these instructions will not appear on
				 * the stack.
				 */
				if (list_is_singular(&func_node->func_stack)) {
					func_addr = old_func;
					func_size = func->old_size;
				} else {
					struct klp_func *prev;

					prev = list_first_or_null_rcu(
						&func_node->func_stack,
						struct klp_func, stack_node);
					func_addr = (unsigned long)prev->new_func;
					func_size = prev->new_size;
				}
				ret = add_func(func_list, func_addr, func_size,
						func->old_name, 0);
				if (ret)
					return ret;
				if (func_addr != old_func) {
					ret = add_func_to_list(check_funcs, &pcheck, old_func,
						func->old_size, func->old_name, 0);
					if (ret)
						return ret;
				}
#endif

				func_addr = (unsigned long)func->new_func;
				func_size = func->new_size;
				ret = add_func(func_list, func_addr, func_size,
						func->old_name, 0);
				if (ret)
					return ret;
			}
		}
	}
	return 0;
}

static bool klp_check_jump_func(void *ws_args, unsigned long pc)
{
	struct walk_stackframe_args *args = ws_args;
+1 −122
Original line number Diff line number Diff line
@@ -59,7 +59,7 @@ struct walk_stackframe_args {
	bool (*check_func)(void *data, int *ret, unsigned long pc);
};

static bool check_jump_insn(unsigned long func_addr)
bool arch_check_jump_insn(unsigned long func_addr)
{
	unsigned long i;
	u32 *insn = (u32*)func_addr;
@@ -73,127 +73,6 @@ static bool check_jump_insn(unsigned long func_addr)
	return false;
}

int arch_klp_check_activeness_func(struct klp_patch *patch, int enable,
				   klp_add_func_t add_func, struct list_head *func_list)
{
	int ret;
	struct klp_object *obj;
	struct klp_func *func;
	unsigned long func_addr = 0;
	unsigned long func_size;
	struct klp_func_node *func_node;

	for (obj = patch->objs; obj->funcs; obj++) {
		for (func = obj->funcs; func->old_name; func++) {
			unsigned long old_func = (unsigned long)func->old_func;

			if (enable) {
				bool need_check_old = false;

				if (func->patched || func->force == KLP_ENFORCEMENT)
					continue;
				/*
				 * When enable, checking the currently
				 * active functions.
				 */
				func_node = klp_find_func_node(func->old_func);
				if (!func_node ||
				    list_empty(&func_node->func_stack)) {
					/*
					 * No patched on this function
					 * [ the origin one ]
					 */
					func_addr = old_func;
					func_size = func->old_size;
				} else {
					/*
					 * Previously patched function
					 * [ the active one ]
					 */
					struct klp_func *prev;

					prev = list_first_or_null_rcu(
						&func_node->func_stack,
						struct klp_func, stack_node);
					func_addr = (unsigned long)prev->new_func;
					func_size = prev->new_size;
				}
				/*
				 * When preemtion is disabled and the
				 * replacement area does not contain a jump
				 * instruction, the migration thread is
				 * scheduled to run stop machine only after the
				 * excution of instructions to be replaced is
				 * complete.
				 */
				if (IS_ENABLED(CONFIG_PREEMPTION) ||
				    IS_ENABLED(CONFIG_LIVEPATCH_BREAKPOINT_NO_STOP_MACHINE) ||
				    (func->force == KLP_NORMAL_FORCE) ||
				    check_jump_insn(func_addr)) {
					ret = add_func(func_list, func_addr, func_size,
							func->old_name, func->force);
					if (ret)
						return ret;
					need_check_old = (func_addr != old_func);
				}
				if (need_check_old) {
					ret = add_func_to_list(check_funcs, &pcheck, old_func,
						func->old_size, func->old_name, func->force);
					if (ret)
						return ret;
				}
			} else {
				/*
				 * When disable, check for the previously
				 * patched function and the function itself
				 * which to be unpatched.
				 */
				func_node = klp_find_func_node(func->old_func);
				if (!func_node)
					return -EINVAL;
#ifdef CONFIG_PREEMPTION
				/*
				 * No scheduling point in the replacement
				 * instructions. Therefore, when preemption is
				 * not enabled, atomic execution is performed
				 * and these instructions will not appear on
				 * the stack.
				 */
				if (list_is_singular(&func_node->func_stack)) {
					func_addr = old_func;
					func_size = func->old_size;
				} else {
					struct klp_func *prev;

					prev = list_first_or_null_rcu(
						&func_node->func_stack,
						struct klp_func, stack_node);
					func_addr = (unsigned long)prev->new_func;
					func_size = prev->new_size;
				}
				ret = add_func(func_list, func_addr,
						func_size, func->old_name, 0);
				if (ret)
					return ret;
				if (func_addr != old_func) {
					ret = add_func_to_list(check_funcs, &pcheck, old_func,
							func->old_size, func->old_name, 0);
					if (ret)
						return ret;
				}
#endif
				func_addr = (unsigned long)func->new_func;
				func_size = func->new_size;
				ret = add_func(func_list, func_addr,
						func_size, func->old_name, 0);
				if (ret)
					return ret;
			}
		}
	}
	return 0;
}

void notrace klp_walk_stackframe(struct stackframe *frame,
		int (*fn)(struct stackframe *, void *),
		struct task_struct *tsk, void *data)
+91 −102
Original line number Diff line number Diff line
@@ -78,29 +78,23 @@ static bool check_jump_insn(unsigned long func_addr)
	return false;
}

int arch_klp_check_activeness_func(struct klp_patch *patch, int enable,
int arch_klp_check_activeness_func(struct klp_func *func, int enable,
				   klp_add_func_t add_func, struct list_head *func_list)
{
	int ret;
	struct klp_object *obj;
	struct klp_func *func;
	unsigned long func_addr, func_size;
	struct klp_func_node *func_node = NULL;

	for (obj = patch->objs; obj->funcs; obj++) {
		for (func = obj->funcs; func->old_name; func++) {
	func_node = klp_find_func_node(func->old_func);

	/* Check func address in stack */
	if (enable) {
		if (func->patched || func->force == KLP_ENFORCEMENT)
					continue;
			return 0;
		/*
		 * When enable, checking the currently
		 * active functions.
		 */
				if (!func_node ||
				    list_empty(&func_node->func_stack)) {
		if (!func_node || list_empty(&func_node->func_stack)) {
			/*
			 * No patched on this function
			 * [ the origin one ]
@@ -114,11 +108,9 @@ int arch_klp_check_activeness_func(struct klp_patch *patch, int enable,
			 */
			struct klp_func *prev;

					prev = list_first_or_null_rcu(
						&func_node->func_stack,
			prev = list_first_or_null_rcu(&func_node->func_stack,
						      struct klp_func, stack_node);
					func_addr = ppc_function_entry(
						(void *)prev->new_func);
			func_addr = ppc_function_entry((void *)prev->new_func);
			func_size = prev->new_size;
		}
		/*
@@ -143,8 +135,7 @@ int arch_klp_check_activeness_func(struct klp_patch *patch, int enable,
		 * When disable, check for the function itself
		 * which to be unpatched.
		 */
				func_addr = ppc_function_entry(
						(void *)func->new_func);
		func_addr = ppc_function_entry((void *)func->new_func);
		func_size = func->new_size;
		ret = add_func(func_list, func_addr,
			       func_size, func->old_name, 0);
@@ -180,7 +171,7 @@ int arch_klp_check_activeness_func(struct klp_patch *patch, int enable,

		if (func_node == NULL ||
		    func_node->arch_data.trampoline.magic != BRANCH_TRAMPOLINE_MAGIC)
					continue;
			return 0;

		func_addr = (unsigned long)&func_node->arch_data.trampoline;
		func_size = sizeof(struct ppc64_klp_btramp_entry);
@@ -190,8 +181,6 @@ int arch_klp_check_activeness_func(struct klp_patch *patch, int enable,
			return ret;
	}
#endif
		}
	}
	return 0;
}

+1 −118
Original line number Diff line number Diff line
@@ -52,7 +52,7 @@ static bool is_jump_insn(u8 *insn)
	return false;
}

static bool check_jump_insn(unsigned long func_addr)
bool arch_check_jump_insn(unsigned long func_addr)
{
	int len = JMP_E9_INSN_SIZE;
	struct insn insn;
@@ -72,123 +72,6 @@ static bool check_jump_insn(unsigned long func_addr)
	return false;
}

int arch_klp_check_activeness_func(struct klp_patch *patch, int enable,
				   klp_add_func_t add_func, struct list_head *func_list)
{
	int ret;
	struct klp_object *obj;
	struct klp_func *func;
	unsigned long func_addr = 0;
	unsigned long func_size;
	struct klp_func_node *func_node = NULL;

	for (obj = patch->objs; obj->funcs; obj++) {
		for (func = obj->funcs; func->old_name; func++) {
			unsigned long old_func = (unsigned long)func->old_func;

			func_node = klp_find_func_node(func->old_func);
			/* Check func address in stack */
			if (enable) {
				bool need_check_old = false;

				if (func->patched || func->force == KLP_ENFORCEMENT)
					continue;
				/*
				 * When enable, checking the currently
				 * active functions.
				 */
				if (!func_node ||
				    list_empty(&func_node->func_stack)) {
					func_addr = old_func;
					func_size = func->old_size;
				} else {
					/*
					 * Previously patched function
					 * [the active one]
					 */
					struct klp_func *prev;

					prev = list_first_or_null_rcu(
						&func_node->func_stack,
						struct klp_func, stack_node);
					func_addr = (unsigned long)prev->new_func;
					func_size = prev->new_size;
				}
				/*
				 * When preemtion is disabled and the
				 * replacement area does not contain a jump
				 * instruction, the migration thread is
				 * scheduled to run stop machine only after the
				 * excution of instructions to be replaced is
				 * complete.
				 */
				if (IS_ENABLED(CONFIG_PREEMPTION) ||
				    IS_ENABLED(CONFIG_LIVEPATCH_BREAKPOINT_NO_STOP_MACHINE) ||
				    (func->force == KLP_NORMAL_FORCE) ||
				    check_jump_insn(func_addr)) {
					ret = add_func(func_list, func_addr, func_size,
							func->old_name, func->force);
					if (ret)
						return ret;
					need_check_old = (func_addr != old_func);
				}
				if (need_check_old) {
					ret = add_func_to_list(check_funcs, &pcheck, old_func,
						func->old_size, func->old_name, func->force);
					if (ret)
						return ret;
				}
			} else {
				/*
				 * When disable, check for the function
				 * itself which to be unpatched.
				 */
				if (!func_node)
					return -EINVAL;
#ifdef CONFIG_PREEMPTION
				/*
				 * No scheduling point in the replacement
				 * instructions. Therefore, when preemption is
				 * not enabled, atomic execution is performed
				 * and these instructions will not appear on
				 * the stack.
				 */
				if (list_is_singular(&func_node->func_stack)) {
					func_addr = old_func;
					func_size = func->old_size;
				} else {
					struct klp_func *prev;

					prev = list_first_or_null_rcu(
						&func_node->func_stack,
						struct klp_func, stack_node);
					func_addr = (unsigned long)prev->new_func;
					func_size = prev->new_size;
				}
				ret = add_func(func_list, func_addr,
						func_size, func->old_name, 0);
				if (ret)
					return ret;
				if (func_addr != old_func) {
					ret = add_func_to_list(check_funcs, &pcheck, old_func,
							func->old_size, func->old_name, 0);
					if (ret)
						return ret;
				}
#endif

				func_addr = (unsigned long)func->new_func;
				func_size = func->new_size;
				ret = add_func(func_list, func_addr,
						func_size, func->old_name, 0);
				if (ret)
					return ret;
			}
		}
	}
	return 0;
}

static void klp_print_stack_trace(void *trace_ptr, int trace_len)
{
	int i;
Loading