diff --git a/arch/arm64/kernel/livepatch.c b/arch/arm64/kernel/livepatch.c index e43afc7871486146de2052fdc1e3172fd3cb26f9..ead6a34bb523453b26f85afb6670924b374f4f66 100644 --- a/arch/arm64/kernel/livepatch.c +++ b/arch/arm64/kernel/livepatch.c @@ -34,6 +34,7 @@ #ifdef CONFIG_LIVEPATCH_WO_FTRACE #include +#include #endif #ifdef CONFIG_ARM64_MODULE_PLTS @@ -288,4 +289,29 @@ void arch_klp_unpatch_func(struct klp_func *func) #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 diff --git a/kernel/livepatch/core.c b/kernel/livepatch/core.c index 4b481176681a39024b68ad67e3f11ed3368fe4b5..1fdb688475e9dc7ff078a3c88577487e4c024bd0 100644 --- a/kernel/livepatch/core.c +++ b/kernel/livepatch/core.c @@ -916,14 +916,31 @@ static void klp_free_patch(struct klp_patch *patch) 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) { +#ifdef CONFIG_LIVEPATCH_WO_FTRACE + int ret; +#endif + if (!func->old_name || !func->new_func) return -EINVAL; if (strlen(func->old_name) >= KSYM_NAME_LEN) 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); func->patched = false; #ifdef CONFIG_LIVEPATCH_FTRACE @@ -1015,18 +1032,19 @@ static int klp_init_object(struct klp_patch *patch, struct klp_object *obj) if (ret) goto put; - klp_for_each_func(obj, func) { - ret = klp_init_func(obj, func); + if (klp_is_object_loaded(obj)) { + ret = klp_init_object_loaded(patch, obj); if (ret) goto out; } - if (klp_is_object_loaded(obj)) { - ret = klp_init_object_loaded(patch, obj); + klp_for_each_func(obj, func) { + ret = klp_init_func(obj, func); if (ret) goto free; } + return 0; free: