提交 b6f7ad60 编写于 作者: C Cheng Jian 提交者: Yang Yingliang

livepatch/arm64: check active func in consistency stack checking

hulk inclusion
category: bugfix
bugzilla: 5507/31358
CVE: NA
---------------------------

When doing consistency stack checking, if we try to patch a
function which has been patched already. We should check the
new function(not the origin func) that is activeness currently,
it's always the first entry in list func_node->func_stack.

Example :
	module : origin			livepatch v1		livepatch v2
	func   : old func A -[enable]=> new func A' -[enable]=> new func A''
	check  :		A			A'

when we try to patch function A to new function A'' by livepatch
v2, but the func A has already patched to function A' by livepatch
v1, so function A' which provided in livepatch v1 is active in the
stack instead of origin function A. Even if the long jump method is
used, we jump to the new function A' using a call without LR, the
origin function A will not appear in the stack. We must check the
active function A' in consistency stack checking.
Signed-off-by: NCheng Jian <cj.chengjian@huawei.com>
Reviewed-By: NXie XiuQi <xiexiuqi@huawei.com>
Signed-off-by: NYang Yingliang <yangyingliang@huawei.com>
上级 27057710
......@@ -47,6 +47,33 @@ static inline bool offset_in_range(unsigned long pc, unsigned long addr,
}
#endif
#define LJMP_INSN_SIZE 4
struct klp_func_node {
struct list_head node;
struct list_head func_stack;
unsigned long old_addr;
#ifdef CONFIG_ARM64_MODULE_PLTS
u32 old_insns[LJMP_INSN_SIZE];
#else
u32 old_insn;
#endif
};
static LIST_HEAD(klp_func_list);
static struct klp_func_node *klp_find_func_node(unsigned long old_addr)
{
struct klp_func_node *func_node;
list_for_each_entry(func_node, &klp_func_list, node) {
if (func_node->old_addr == old_addr)
return func_node;
}
return NULL;
}
struct walk_stackframe_args {
struct klp_patch *patch;
int enable;
......@@ -71,6 +98,7 @@ static int klp_check_activeness_func(struct stackframe *frame, void *data)
struct klp_func *func;
unsigned long func_addr, func_size;
const char *func_name;
struct klp_func_node *func_node;
if (args->ret)
return args->ret;
......@@ -80,9 +108,34 @@ static int klp_check_activeness_func(struct stackframe *frame, void *data)
if (args->enable) {
if (func->force)
continue;
func_addr = func->old_addr;
func_size = func->old_size;
/*
* When enable, checking the currently
* active functions.
*/
func_node = klp_find_func_node(func->old_addr);
if (!func_node ||
list_empty(&func_node->func_stack)) {
func_addr = func->old_addr;
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;
}
} else {
/*
* When disable, check for the function
* itself which to be unpatched.
*/
func_addr = (unsigned long)func->new_func;
func_size = func->new_size;
}
......@@ -153,33 +206,6 @@ int klp_check_calltrace(struct klp_patch *patch, int enable)
}
#ifdef CONFIG_LIVEPATCH_WO_FTRACE
#define LJMP_INSN_SIZE 4
struct klp_func_node {
struct list_head node;
struct list_head func_stack;
unsigned long old_addr;
#ifdef CONFIG_ARM64_MODULE_PLTS
u32 old_insns[LJMP_INSN_SIZE];
#else
u32 old_insn;
#endif
};
static LIST_HEAD(klp_func_list);
static struct klp_func_node *klp_find_func_node(unsigned long old_addr)
{
struct klp_func_node *func_node;
list_for_each_entry(func_node, &klp_func_list, node) {
if (func_node->old_addr == old_addr)
return func_node;
}
return NULL;
}
int arch_klp_patch_func(struct klp_func *func)
{
struct klp_func_node *func_node;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册