Commit 000c0197 authored by Ye Weihua's avatar Ye Weihua Committed by Zheng Zengkai
Browse files

livepatch: put memory alloc and free out stop machine



hulk inclusion
category: feature
bugzilla: 51924
CVE: NA

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

When a livepatch is insmod, stop machine will stop other cores, which
interrupts services. Therefore, the shorter the stop machine duration,
the better. The application and release of memory from the stop machine
can shorten the time for stopping the machine.

Especially, module_alloc and module_memfree is a kind of vmalloc, that
may sleep when called. So it is not permitted to use them in stop machine
context.

Signed-off-by: default avatarYe Weihua <yeweihua4@huawei.com>
Reviewed-by: default avatarYang Jihong <yangjihong1@huawei.com>
Signed-off-by: default avatarZheng Zengkai <zhengzengkai@huawei.com>
parent 673d37a2
Loading
Loading
Loading
Loading
+31 −3
Original line number Diff line number Diff line
@@ -229,7 +229,7 @@ int arch_klp_patch_func(struct klp_func *func)

	func_node = klp_find_func_node(func->old_func);
	if (!func_node) {
		func_node = kzalloc(sizeof(*func_node), GFP_ATOMIC);
		func_node = func->func_node;
		if (!func_node)
			return -ENOMEM;

@@ -246,7 +246,6 @@ int arch_klp_patch_func(struct klp_func *func)
		ret = arm_insn_read(func->old_func, &func_node->old_insn);
#endif
		if (ret) {
			kfree(func_node);
			return -EPERM;
		}
		list_add_rcu(&func_node->node, &klp_func_list);
@@ -308,7 +307,6 @@ void arch_klp_unpatch_func(struct klp_func *func)
#endif
		list_del_rcu(&func->stack_node);
		list_del_rcu(&func_node->node);
		kfree(func_node);
	} else {
		list_del_rcu(&func->stack_node);
		next_func = list_first_or_null_rcu(&func_node->func_stack,
@@ -364,3 +362,33 @@ int arch_klp_func_can_patch(struct klp_func *func)
	return 0;
}
#endif /* #ifdef CONFIG_ARM_MODULE_PLTS */

void arch_klp_mem_prepare(struct klp_patch *patch)
{
	struct klp_object *obj;
	struct klp_func *func;

	klp_for_each_object(patch, obj) {
		klp_for_each_func(obj, func) {
			func->func_node = kzalloc(sizeof(struct klp_func_node),
					GFP_ATOMIC);
		}
	}
}

void arch_klp_mem_recycle(struct klp_patch *patch)
{
	struct klp_object *obj;
	struct klp_func *func;
	struct klp_func_node *func_node;

	klp_for_each_object(patch, obj) {
		klp_for_each_func(obj, func) {
			func_node = func->func_node;
			if (func_node && list_is_singular(&func_node->func_stack)) {
				kfree(func_node);
				func->func_node = NULL;
			}
		}
	}
}
+31 −4
Original line number Diff line number Diff line
@@ -215,7 +215,7 @@ int arch_klp_patch_func(struct klp_func *func)

	func_node = klp_find_func_node((unsigned long)func->old_func);
	if (!func_node) {
		func_node = kzalloc(sizeof(*func_node), GFP_ATOMIC);
		func_node = func->func_node;
		if (!func_node)
			return -ENOMEM;
		memory_flag = 1;
@@ -235,7 +235,6 @@ int arch_klp_patch_func(struct klp_func *func)
					&func_node->old_insn);
#endif
		if (ret) {
			kfree(func_node);
			return -EPERM;
		}

@@ -276,7 +275,6 @@ int arch_klp_patch_func(struct klp_func *func)
	list_del_rcu(&func->stack_node);
	if (memory_flag) {
		list_del_rcu(&func_node->node);
		kfree(func_node);
	}

	return -EPERM;
@@ -306,7 +304,6 @@ void arch_klp_unpatch_func(struct klp_func *func)
#endif
		list_del_rcu(&func->stack_node);
		list_del_rcu(&func_node->node);
		kfree(func_node);

#ifdef CONFIG_ARM64_MODULE_PLTS
		for (i = 0; i < LJMP_INSN_SIZE; i++) {
@@ -372,3 +369,33 @@ int arch_klp_func_can_patch(struct klp_func *func)
	return 0;
}
#endif

void arch_klp_mem_prepare(struct klp_patch *patch)
{
	struct klp_object *obj;
	struct klp_func *func;

	klp_for_each_object(patch, obj) {
		klp_for_each_func(obj, func) {
			func->func_node = kzalloc(sizeof(struct klp_func_node),
					GFP_ATOMIC);
		}
	}
}

void arch_klp_mem_recycle(struct klp_patch *patch)
{
	struct klp_object *obj;
	struct klp_func *func;
	struct klp_func_node *func_node;

	klp_for_each_object(patch, obj) {
		klp_for_each_func(obj, func) {
			func_node = func->func_node;
			if (func_node && list_is_singular(&func_node->func_stack)) {
				kfree(func_node);
				func->func_node = NULL;
			}
		}
	}
}
+31 −4
Original line number Diff line number Diff line
@@ -254,7 +254,7 @@ int arch_klp_patch_func(struct klp_func *func)

	func_node = klp_find_func_node(func->old_func);
	if (!func_node) {
		func_node = kzalloc(sizeof(*func_node), GFP_ATOMIC);
		func_node = func->func_node;
		if (!func_node)
			return -ENOMEM;

@@ -265,7 +265,6 @@ int arch_klp_patch_func(struct klp_func *func)
			ret = copy_from_kernel_nofault(&func_node->old_insns[i],
				((u32 *)func->old_func) + i, LJMP_INSN_SIZE);
			if (ret) {
				kfree(func_node);
				return -EPERM;
			}
		}
@@ -309,7 +308,6 @@ int arch_klp_patch_func(struct klp_func *func)
	list_del_rcu(&func->stack_node);
	if (memory_flag) {
		list_del_rcu(&func_node->node);
		kfree(func_node);
	}

	return -EPERM;
@@ -331,7 +329,6 @@ void arch_klp_unpatch_func(struct klp_func *func)

		list_del_rcu(&func->stack_node);
		list_del_rcu(&func_node->node);
		kfree(func_node);

		for (i = 0; i < LJMP_INSN_SIZE; i++)
			patch_instruction((struct ppc_inst *)(((u32 *)pc) + i),
@@ -383,4 +380,34 @@ int arch_klp_func_can_patch(struct klp_func *func)
	}
	return 0;
}

void arch_klp_mem_prepare(struct klp_patch *patch)
{
	struct klp_object *obj;
	struct klp_func *func;

	klp_for_each_object(patch, obj) {
		klp_for_each_func(obj, func) {
			func->func_node = kzalloc(sizeof(struct klp_func_node),
					GFP_ATOMIC);
		}
	}
}

void arch_klp_mem_recycle(struct klp_patch *patch)
{
	struct klp_object *obj;
	struct klp_func *func;
	struct klp_func_node *func_node;

	klp_for_each_object(patch, obj) {
		klp_for_each_func(obj, func) {
			func_node = func->func_node;
			if (func_node && list_is_singular(&func_node->func_stack)) {
				kfree(func_node);
				func->func_node = NULL;
			}
		}
	}
}
#endif
+30 −4
Original line number Diff line number Diff line
@@ -351,7 +351,7 @@ int arch_klp_patch_func(struct klp_func *func)

	func_node = klp_find_func_node(func->old_func);
	if (!func_node) {
		func_node = module_alloc(sizeof(*func_node));
		func_node = func->func_node;
		if (!func_node)
			return -ENOMEM;

@@ -362,7 +362,6 @@ int arch_klp_patch_func(struct klp_func *func)
			ret = copy_from_kernel_nofault(&func_node->old_insns[i],
				((u32 *)func->old_func) + i, 4);
			if (ret) {
				module_memfree(func_node);
				return -EPERM;
			}
		}
@@ -393,7 +392,6 @@ int arch_klp_patch_func(struct klp_func *func)
	list_del_rcu(&func->stack_node);
	if (memory_flag) {
		list_del_rcu(&func_node->node);
		module_memfree(func_node);
	}

	return -EPERM;
@@ -415,7 +413,6 @@ void arch_klp_unpatch_func(struct klp_func *func)

		list_del_rcu(&func->stack_node);
		list_del_rcu(&func_node->node);
		module_memfree(func_node);

		for (i = 0; i < LJMP_INSN_SIZE; i++)
			patch_instruction((struct ppc_inst *)((u32 *)pc + i),
@@ -498,4 +495,33 @@ int arch_klp_init_func(struct klp_object *obj, struct klp_func *func)

	return 0;
}

void arch_klp_mem_prepare(struct klp_patch *patch)
{
	struct klp_object *obj;
	struct klp_func *func;

	klp_for_each_object(patch, obj) {
		klp_for_each_func(obj, func) {
			func->func_node = module_alloc(sizeof(struct klp_func_node));
		}
	}
}

void arch_klp_mem_recycle(struct klp_patch *patch)
{
	struct klp_object *obj;
	struct klp_func *func;
	struct klp_func_node *func_node;

	klp_for_each_object(patch, obj) {
		klp_for_each_func(obj, func) {
			func_node = func->func_node;
			if (func_node && list_is_singular(&func_node->func_stack)) {
				module_memfree(func_node);
				func->func_node = NULL;
			}
		}
	}
}
#endif
+31 −3
Original line number Diff line number Diff line
@@ -284,7 +284,7 @@ int arch_klp_patch_func(struct klp_func *func)
	func_node = klp_find_func_node(func->old_func);
	ip = (unsigned long)func->old_func;
	if (!func_node) {
		func_node = kzalloc(sizeof(*func_node), GFP_ATOMIC);
		func_node = func->func_node;
		if (!func_node)
			return -ENOMEM;

@@ -293,7 +293,6 @@ int arch_klp_patch_func(struct klp_func *func)
		ret = copy_from_kernel_nofault(func_node->old_code,
					(void *)ip, JMP_E9_INSN_SIZE);
		if (ret) {
			kfree(func_node);
			return -EPERM;
		}
		list_add_rcu(&func_node->node, &klp_func_list);
@@ -322,7 +321,6 @@ void arch_klp_unpatch_func(struct klp_func *func)
		list_del_rcu(&func->stack_node);
		list_del_rcu(&func_node->node);
		new = klp_old_code(func_node->old_code);
		kfree(func_node);
	} else {
		list_del_rcu(&func->stack_node);
		next_func = list_first_or_null_rcu(&func_node->func_stack,
@@ -335,4 +333,34 @@ void arch_klp_unpatch_func(struct klp_func *func)
	/* replace the text with the new text */
	text_poke((void *)ip, new, JMP_E9_INSN_SIZE);
}

void arch_klp_mem_prepare(struct klp_patch *patch)
{
	struct klp_object *obj;
	struct klp_func *func;

	klp_for_each_object(patch, obj) {
		klp_for_each_func(obj, func) {
			func->func_node = kzalloc(sizeof(struct klp_func_node),
					GFP_ATOMIC);
		}
	}
}

void arch_klp_mem_recycle(struct klp_patch *patch)
{
	struct klp_object *obj;
	struct klp_func *func;
	struct klp_func_node *func_node;

	klp_for_each_object(patch, obj) {
		klp_for_each_func(obj, func) {
			func_node = func->func_node;
			if (func_node && list_is_singular(&func_node->func_stack)) {
				kfree(func_node);
				func->func_node = NULL;
			}
		}
	}
}
#endif
Loading