提交 453d3845 编写于 作者: C Cheng Jian 提交者: Xie XiuQi

livepatch/arm64: fix func size less than limit

euler inclusion
category: feature
Bugzilla: 5507
CVE: N/A

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

we need to modify the first 4 instructions of a livepatch function to
complete the long jump if offset out of short-range. So it's important
that this function must have more than 4 instructions, so we checked it
when the livepatch module insmod.

In fact, this corner case is highly unlikely tooccur on arm64, but it's
still an effective and meaningful check to avoid crash by doing this.
Signed-off-by: NCheng Jian <cj.chengjian@huawei.com>
Reviewed-by: NLi Bin <huawei.libin@huawei.com>
Signed-off-by: NYang Yingliang <yangyingliang@huawei.com>
上级 96bdd177
...@@ -34,6 +34,7 @@ ...@@ -34,6 +34,7 @@
#ifdef CONFIG_LIVEPATCH_WO_FTRACE #ifdef CONFIG_LIVEPATCH_WO_FTRACE
#include <linux/sched/debug.h> #include <linux/sched/debug.h>
#include <linux/kallsyms.h>
#endif #endif
#ifdef CONFIG_ARM64_MODULE_PLTS #ifdef CONFIG_ARM64_MODULE_PLTS
...@@ -288,4 +289,29 @@ void arch_klp_unpatch_func(struct klp_func *func) ...@@ -288,4 +289,29 @@ void arch_klp_unpatch_func(struct klp_func *func)
#endif #endif
} }
} }
#ifdef CONFIG_ARM64_MODULE_PLTS
/* return 0 if the func can be patched */
int arch_klp_func_can_patch(struct klp_func *func)
{
unsigned long pc = func->old_addr;
unsigned long new_addr = (unsigned long)func->new_func;
unsigned long old_size = func->old_size;
if ((long)old_size <= 0)
return -EINVAL;
if (!offset_in_range(pc, new_addr, SZ_128M) &&
(old_size < LJMP_INSN_SIZE * sizeof(u32))) {
pr_err("func %s size less than limit\n", func->old_name);
return -EPERM;
}
return 0;
}
#else
int arch_klp_func_can_patch(struct klp_func *func)
{
return 0;
}
#endif /* #ifdef CONFIG_ARM64_MODULE_PLTS */
#endif #endif
...@@ -916,14 +916,31 @@ static void klp_free_patch(struct klp_patch *patch) ...@@ -916,14 +916,31 @@ static void klp_free_patch(struct klp_patch *patch)
list_del(&patch->list); list_del(&patch->list);
} }
#ifdef CONFIG_LIVEPATCH_WO_FTRACE
int __weak arch_klp_func_can_patch(struct klp_func *func)
{
return 0;
}
#endif
static int klp_init_func(struct klp_object *obj, struct klp_func *func) static int klp_init_func(struct klp_object *obj, struct klp_func *func)
{ {
#ifdef CONFIG_LIVEPATCH_WO_FTRACE
int ret;
#endif
if (!func->old_name || !func->new_func) if (!func->old_name || !func->new_func)
return -EINVAL; return -EINVAL;
if (strlen(func->old_name) >= KSYM_NAME_LEN) if (strlen(func->old_name) >= KSYM_NAME_LEN)
return -EINVAL; return -EINVAL;
#ifdef CONFIG_LIVEPATCH_WO_FTRACE
ret = arch_klp_func_can_patch(func);
if (ret)
return ret;
#endif
INIT_LIST_HEAD(&func->stack_node); INIT_LIST_HEAD(&func->stack_node);
func->patched = false; func->patched = false;
#ifdef CONFIG_LIVEPATCH_FTRACE #ifdef CONFIG_LIVEPATCH_FTRACE
...@@ -1015,18 +1032,19 @@ static int klp_init_object(struct klp_patch *patch, struct klp_object *obj) ...@@ -1015,18 +1032,19 @@ static int klp_init_object(struct klp_patch *patch, struct klp_object *obj)
if (ret) if (ret)
goto put; goto put;
klp_for_each_func(obj, func) { if (klp_is_object_loaded(obj)) {
ret = klp_init_func(obj, func); ret = klp_init_object_loaded(patch, obj);
if (ret) if (ret)
goto out; goto out;
} }
if (klp_is_object_loaded(obj)) { klp_for_each_func(obj, func) {
ret = klp_init_object_loaded(patch, obj); ret = klp_init_func(obj, func);
if (ret) if (ret)
goto free; goto free;
} }
return 0; return 0;
free: free:
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册