Loading arch/x86/include/asm/livepatch.h +2 −2 Original line number Original line Diff line number Diff line Loading @@ -32,7 +32,7 @@ static inline int klp_check_compiler_support(void) #endif #endif return 0; return 0; } } extern int klp_write_module_reloc(struct module *mod, unsigned long type, int klp_write_module_reloc(struct module *mod, unsigned long type, unsigned long loc, unsigned long value); unsigned long loc, unsigned long value); static inline void klp_arch_set_pc(struct pt_regs *regs, unsigned long ip) static inline void klp_arch_set_pc(struct pt_regs *regs, unsigned long ip) Loading include/linux/livepatch.h +4 −4 Original line number Original line Diff line number Diff line Loading @@ -123,10 +123,10 @@ struct klp_patch { enum klp_state state; enum klp_state state; }; }; extern int klp_register_patch(struct klp_patch *); int klp_register_patch(struct klp_patch *); extern int klp_unregister_patch(struct klp_patch *); int klp_unregister_patch(struct klp_patch *); extern int klp_enable_patch(struct klp_patch *); int klp_enable_patch(struct klp_patch *); extern int klp_disable_patch(struct klp_patch *); int klp_disable_patch(struct klp_patch *); #endif /* CONFIG_LIVEPATCH */ #endif /* CONFIG_LIVEPATCH */ Loading kernel/livepatch/core.c +17 −52 Original line number Original line Diff line number Diff line Loading @@ -335,32 +335,20 @@ unlock: rcu_read_unlock(); rcu_read_unlock(); } } static int klp_disable_func(struct klp_func *func) static void klp_disable_func(struct klp_func *func) { { struct klp_ops *ops; struct klp_ops *ops; int ret; if (WARN_ON(func->state != KLP_ENABLED)) return -EINVAL; if (WARN_ON(!func->old_addr)) WARN_ON(func->state != KLP_ENABLED); return -EINVAL; WARN_ON(!func->old_addr); ops = klp_find_ops(func->old_addr); ops = klp_find_ops(func->old_addr); if (WARN_ON(!ops)) if (WARN_ON(!ops)) return -EINVAL; return; if (list_is_singular(&ops->func_stack)) { if (list_is_singular(&ops->func_stack)) { ret = unregister_ftrace_function(&ops->fops); WARN_ON(unregister_ftrace_function(&ops->fops)); if (ret) { WARN_ON(ftrace_set_filter_ip(&ops->fops, func->old_addr, 1, 0)); pr_err("failed to unregister ftrace handler for function '%s' (%d)\n", func->old_name, ret); return ret; } ret = ftrace_set_filter_ip(&ops->fops, func->old_addr, 1, 0); if (ret) pr_warn("function unregister succeeded but failed to clear the filter\n"); list_del_rcu(&func->stack_node); list_del_rcu(&func->stack_node); list_del(&ops->node); list_del(&ops->node); Loading @@ -370,8 +358,6 @@ static int klp_disable_func(struct klp_func *func) } } func->state = KLP_DISABLED; func->state = KLP_DISABLED; return 0; } } static int klp_enable_func(struct klp_func *func) static int klp_enable_func(struct klp_func *func) Loading Loading @@ -432,23 +418,15 @@ err: return ret; return ret; } } static int klp_disable_object(struct klp_object *obj) static void klp_disable_object(struct klp_object *obj) { { struct klp_func *func; struct klp_func *func; int ret; for (func = obj->funcs; func->old_name; func++) { for (func = obj->funcs; func->old_name; func++) if (func->state != KLP_ENABLED) if (func->state == KLP_ENABLED) continue; klp_disable_func(func); ret = klp_disable_func(func); if (ret) return ret; } obj->state = KLP_DISABLED; obj->state = KLP_DISABLED; return 0; } } static int klp_enable_object(struct klp_object *obj) static int klp_enable_object(struct klp_object *obj) Loading @@ -464,22 +442,19 @@ static int klp_enable_object(struct klp_object *obj) for (func = obj->funcs; func->old_name; func++) { for (func = obj->funcs; func->old_name; func++) { ret = klp_enable_func(func); ret = klp_enable_func(func); if (ret) if (ret) { goto unregister; klp_disable_object(obj); return ret; } } } obj->state = KLP_ENABLED; obj->state = KLP_ENABLED; return 0; return 0; unregister: WARN_ON(klp_disable_object(obj)); return ret; } } static int __klp_disable_patch(struct klp_patch *patch) static int __klp_disable_patch(struct klp_patch *patch) { { struct klp_object *obj; struct klp_object *obj; int ret; /* enforce stacking: only the last enabled patch can be disabled */ /* enforce stacking: only the last enabled patch can be disabled */ if (!list_is_last(&patch->list, &klp_patches) && if (!list_is_last(&patch->list, &klp_patches) && Loading @@ -489,12 +464,8 @@ static int __klp_disable_patch(struct klp_patch *patch) pr_notice("disabling patch '%s'\n", patch->mod->name); pr_notice("disabling patch '%s'\n", patch->mod->name); for (obj = patch->objs; obj->funcs; obj++) { for (obj = patch->objs; obj->funcs; obj++) { if (obj->state != KLP_ENABLED) if (obj->state == KLP_ENABLED) continue; klp_disable_object(obj); ret = klp_disable_object(obj); if (ret) return ret; } } patch->state = KLP_DISABLED; patch->state = KLP_DISABLED; Loading Loading @@ -553,8 +524,6 @@ static int __klp_enable_patch(struct klp_patch *patch) pr_notice("enabling patch '%s'\n", patch->mod->name); pr_notice("enabling patch '%s'\n", patch->mod->name); for (obj = patch->objs; obj->funcs; obj++) { for (obj = patch->objs; obj->funcs; obj++) { klp_find_object_module(obj); if (!klp_is_object_loaded(obj)) if (!klp_is_object_loaded(obj)) continue; continue; Loading Loading @@ -945,7 +914,6 @@ static void klp_module_notify_going(struct klp_patch *patch, { { struct module *pmod = patch->mod; struct module *pmod = patch->mod; struct module *mod = obj->mod; struct module *mod = obj->mod; int ret; if (patch->state == KLP_DISABLED) if (patch->state == KLP_DISABLED) goto disabled; goto disabled; Loading @@ -953,10 +921,7 @@ static void klp_module_notify_going(struct klp_patch *patch, pr_notice("reverting patch '%s' on unloading module '%s'\n", pr_notice("reverting patch '%s' on unloading module '%s'\n", pmod->name, mod->name); pmod->name, mod->name); ret = klp_disable_object(obj); klp_disable_object(obj); if (ret) pr_warn("failed to revert patch '%s' on module '%s' (%d)\n", pmod->name, mod->name, ret); disabled: disabled: klp_free_object_loaded(obj); klp_free_object_loaded(obj); Loading Loading
arch/x86/include/asm/livepatch.h +2 −2 Original line number Original line Diff line number Diff line Loading @@ -32,7 +32,7 @@ static inline int klp_check_compiler_support(void) #endif #endif return 0; return 0; } } extern int klp_write_module_reloc(struct module *mod, unsigned long type, int klp_write_module_reloc(struct module *mod, unsigned long type, unsigned long loc, unsigned long value); unsigned long loc, unsigned long value); static inline void klp_arch_set_pc(struct pt_regs *regs, unsigned long ip) static inline void klp_arch_set_pc(struct pt_regs *regs, unsigned long ip) Loading
include/linux/livepatch.h +4 −4 Original line number Original line Diff line number Diff line Loading @@ -123,10 +123,10 @@ struct klp_patch { enum klp_state state; enum klp_state state; }; }; extern int klp_register_patch(struct klp_patch *); int klp_register_patch(struct klp_patch *); extern int klp_unregister_patch(struct klp_patch *); int klp_unregister_patch(struct klp_patch *); extern int klp_enable_patch(struct klp_patch *); int klp_enable_patch(struct klp_patch *); extern int klp_disable_patch(struct klp_patch *); int klp_disable_patch(struct klp_patch *); #endif /* CONFIG_LIVEPATCH */ #endif /* CONFIG_LIVEPATCH */ Loading
kernel/livepatch/core.c +17 −52 Original line number Original line Diff line number Diff line Loading @@ -335,32 +335,20 @@ unlock: rcu_read_unlock(); rcu_read_unlock(); } } static int klp_disable_func(struct klp_func *func) static void klp_disable_func(struct klp_func *func) { { struct klp_ops *ops; struct klp_ops *ops; int ret; if (WARN_ON(func->state != KLP_ENABLED)) return -EINVAL; if (WARN_ON(!func->old_addr)) WARN_ON(func->state != KLP_ENABLED); return -EINVAL; WARN_ON(!func->old_addr); ops = klp_find_ops(func->old_addr); ops = klp_find_ops(func->old_addr); if (WARN_ON(!ops)) if (WARN_ON(!ops)) return -EINVAL; return; if (list_is_singular(&ops->func_stack)) { if (list_is_singular(&ops->func_stack)) { ret = unregister_ftrace_function(&ops->fops); WARN_ON(unregister_ftrace_function(&ops->fops)); if (ret) { WARN_ON(ftrace_set_filter_ip(&ops->fops, func->old_addr, 1, 0)); pr_err("failed to unregister ftrace handler for function '%s' (%d)\n", func->old_name, ret); return ret; } ret = ftrace_set_filter_ip(&ops->fops, func->old_addr, 1, 0); if (ret) pr_warn("function unregister succeeded but failed to clear the filter\n"); list_del_rcu(&func->stack_node); list_del_rcu(&func->stack_node); list_del(&ops->node); list_del(&ops->node); Loading @@ -370,8 +358,6 @@ static int klp_disable_func(struct klp_func *func) } } func->state = KLP_DISABLED; func->state = KLP_DISABLED; return 0; } } static int klp_enable_func(struct klp_func *func) static int klp_enable_func(struct klp_func *func) Loading Loading @@ -432,23 +418,15 @@ err: return ret; return ret; } } static int klp_disable_object(struct klp_object *obj) static void klp_disable_object(struct klp_object *obj) { { struct klp_func *func; struct klp_func *func; int ret; for (func = obj->funcs; func->old_name; func++) { for (func = obj->funcs; func->old_name; func++) if (func->state != KLP_ENABLED) if (func->state == KLP_ENABLED) continue; klp_disable_func(func); ret = klp_disable_func(func); if (ret) return ret; } obj->state = KLP_DISABLED; obj->state = KLP_DISABLED; return 0; } } static int klp_enable_object(struct klp_object *obj) static int klp_enable_object(struct klp_object *obj) Loading @@ -464,22 +442,19 @@ static int klp_enable_object(struct klp_object *obj) for (func = obj->funcs; func->old_name; func++) { for (func = obj->funcs; func->old_name; func++) { ret = klp_enable_func(func); ret = klp_enable_func(func); if (ret) if (ret) { goto unregister; klp_disable_object(obj); return ret; } } } obj->state = KLP_ENABLED; obj->state = KLP_ENABLED; return 0; return 0; unregister: WARN_ON(klp_disable_object(obj)); return ret; } } static int __klp_disable_patch(struct klp_patch *patch) static int __klp_disable_patch(struct klp_patch *patch) { { struct klp_object *obj; struct klp_object *obj; int ret; /* enforce stacking: only the last enabled patch can be disabled */ /* enforce stacking: only the last enabled patch can be disabled */ if (!list_is_last(&patch->list, &klp_patches) && if (!list_is_last(&patch->list, &klp_patches) && Loading @@ -489,12 +464,8 @@ static int __klp_disable_patch(struct klp_patch *patch) pr_notice("disabling patch '%s'\n", patch->mod->name); pr_notice("disabling patch '%s'\n", patch->mod->name); for (obj = patch->objs; obj->funcs; obj++) { for (obj = patch->objs; obj->funcs; obj++) { if (obj->state != KLP_ENABLED) if (obj->state == KLP_ENABLED) continue; klp_disable_object(obj); ret = klp_disable_object(obj); if (ret) return ret; } } patch->state = KLP_DISABLED; patch->state = KLP_DISABLED; Loading Loading @@ -553,8 +524,6 @@ static int __klp_enable_patch(struct klp_patch *patch) pr_notice("enabling patch '%s'\n", patch->mod->name); pr_notice("enabling patch '%s'\n", patch->mod->name); for (obj = patch->objs; obj->funcs; obj++) { for (obj = patch->objs; obj->funcs; obj++) { klp_find_object_module(obj); if (!klp_is_object_loaded(obj)) if (!klp_is_object_loaded(obj)) continue; continue; Loading Loading @@ -945,7 +914,6 @@ static void klp_module_notify_going(struct klp_patch *patch, { { struct module *pmod = patch->mod; struct module *pmod = patch->mod; struct module *mod = obj->mod; struct module *mod = obj->mod; int ret; if (patch->state == KLP_DISABLED) if (patch->state == KLP_DISABLED) goto disabled; goto disabled; Loading @@ -953,10 +921,7 @@ static void klp_module_notify_going(struct klp_patch *patch, pr_notice("reverting patch '%s' on unloading module '%s'\n", pr_notice("reverting patch '%s' on unloading module '%s'\n", pmod->name, mod->name); pmod->name, mod->name); ret = klp_disable_object(obj); klp_disable_object(obj); if (ret) pr_warn("failed to revert patch '%s' on module '%s' (%d)\n", pmod->name, mod->name, ret); disabled: disabled: klp_free_object_loaded(obj); klp_free_object_loaded(obj); Loading