提交 7834e94c 编写于 作者: C Cheng Jian 提交者: Zheng Zengkai

livepatch/arm64: Fix func size less than limit

euler inclusion
category: feature
bugzilla: 51921
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 to occur 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>
Signed-off-by: NWang ShaoBo <bobo.shaobowang@huawei.com>
Signed-off-by: NDong Kai <dongkai11@huawei.com>
Signed-off-by: NYe Weihua <yeweihua4@huawei.com>
Reviewed-by: NYang Jihong <yangjihong1@huawei.com>
Signed-off-by: NZheng Zengkai <zhengzengkai@huawei.com>
上级 e429c61d
...@@ -32,6 +32,7 @@ ...@@ -32,6 +32,7 @@
#include <asm/ptrace.h> #include <asm/ptrace.h>
#include <linux/ftrace.h> #include <linux/ftrace.h>
#include <linux/sched/debug.h> #include <linux/sched/debug.h>
#include <linux/kallsyms.h>
#ifdef CONFIG_ARM64_MODULE_PLTS #ifdef CONFIG_ARM64_MODULE_PLTS
static inline bool offset_in_range(unsigned long pc, unsigned long addr, static inline bool offset_in_range(unsigned long pc, unsigned long addr,
...@@ -295,3 +296,28 @@ void arch_klp_unpatch_func(struct klp_func *func) ...@@ -295,3 +296,28 @@ 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 = (unsigned long)func->old_func;
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
...@@ -878,8 +878,19 @@ void klp_free_replaced_patches_async(struct klp_patch *new_patch) ...@@ -878,8 +878,19 @@ void klp_free_replaced_patches_async(struct klp_patch *new_patch)
} }
} }
#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) if (!func->old_name)
return -EINVAL; return -EINVAL;
...@@ -895,6 +906,12 @@ static int klp_init_func(struct klp_object *obj, struct klp_func *func) ...@@ -895,6 +906,12 @@ static int klp_init_func(struct klp_object *obj, struct klp_func *func)
INIT_LIST_HEAD(&func->stack_node); INIT_LIST_HEAD(&func->stack_node);
func->patched = false; func->patched = false;
#ifdef CONFIG_LIVEPATCH_WO_FTRACE
ret = arch_klp_func_can_patch(func);
if (ret)
return ret;
#endif
#ifdef CONFIG_LIVEPATCH_PER_TASK_CONSISTENCY #ifdef CONFIG_LIVEPATCH_PER_TASK_CONSISTENCY
func->transition = false; func->transition = false;
#endif #endif
...@@ -1002,14 +1019,23 @@ static int klp_init_object(struct klp_patch *patch, struct klp_object *obj) ...@@ -1002,14 +1019,23 @@ static int klp_init_object(struct klp_patch *patch, struct klp_object *obj)
if (ret) if (ret)
goto out; goto out;
klp_for_each_func(obj, func) { /*
ret = klp_init_func(obj, func); * For livepatch without ftrace, we need to modify the first N
* instructions of the to-be-patched func. So should check if the
* func length enough to allow this modification.
*
* We add check hook in klp_init_func and will using the old_size
* internally, so the klp_init_object_loaded should called first
* to fill the klp_func struct.
*/
if (klp_is_object_loaded(obj)) {
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 out; goto out;
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册