Skip to content

Commit

Permalink
livepatch: simplify disable error path
Browse files Browse the repository at this point in the history
If registering the function with ftrace has previously succeeded,
unregistering will almost never fail.  Even if it does, it's not a fatal
error.  We can still carry on and disable the klp_func from being used
by removing it from the klp_ops func stack.

Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com>
Reviewed-by: Miroslav Benes <mbenes@suse.cz>
Reviewed-by: Petr Mladek <pmladek@suse.cz>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
  • Loading branch information
Josh Poimboeuf authored and Jiri Kosina committed Feb 18, 2015
1 parent 4421f8f commit 0937e3b
Showing 1 changed file with 17 additions and 50 deletions.
67 changes: 17 additions & 50 deletions kernel/livepatch/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -322,32 +322,20 @@ static void notrace klp_ftrace_handler(unsigned long ip,
klp_arch_set_pc(regs, (unsigned long)func->new_func);
}

static int klp_disable_func(struct klp_func *func)
static void klp_disable_func(struct klp_func *func)
{
struct klp_ops *ops;
int ret;

if (WARN_ON(func->state != KLP_ENABLED))
return -EINVAL;

if (WARN_ON(!func->old_addr))
return -EINVAL;
WARN_ON(func->state != KLP_ENABLED);
WARN_ON(!func->old_addr);

ops = klp_find_ops(func->old_addr);
if (WARN_ON(!ops))
return -EINVAL;
return;

if (list_is_singular(&ops->func_stack)) {
ret = unregister_ftrace_function(&ops->fops);
if (ret) {
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");
WARN_ON(unregister_ftrace_function(&ops->fops));
WARN_ON(ftrace_set_filter_ip(&ops->fops, func->old_addr, 1, 0));

list_del_rcu(&func->stack_node);
list_del(&ops->node);
Expand All @@ -357,8 +345,6 @@ static int klp_disable_func(struct klp_func *func)
}

func->state = KLP_DISABLED;

return 0;
}

static int klp_enable_func(struct klp_func *func)
Expand Down Expand Up @@ -419,23 +405,15 @@ static int klp_enable_func(struct klp_func *func)
return ret;
}

static int klp_disable_object(struct klp_object *obj)
static void klp_disable_object(struct klp_object *obj)
{
struct klp_func *func;
int ret;

for (func = obj->funcs; func->old_name; func++) {
if (func->state != KLP_ENABLED)
continue;

ret = klp_disable_func(func);
if (ret)
return ret;
}
for (func = obj->funcs; func->old_name; func++)
if (func->state == KLP_ENABLED)
klp_disable_func(func);

obj->state = KLP_DISABLED;

return 0;
}

static int klp_enable_object(struct klp_object *obj)
Expand All @@ -451,22 +429,19 @@ static int klp_enable_object(struct klp_object *obj)

for (func = obj->funcs; func->old_name; func++) {
ret = klp_enable_func(func);
if (ret)
goto unregister;
if (ret) {
klp_disable_object(obj);
return ret;
}
}
obj->state = KLP_ENABLED;

return 0;

unregister:
WARN_ON(klp_disable_object(obj));
return ret;
}

static int __klp_disable_patch(struct klp_patch *patch)
{
struct klp_object *obj;
int ret;

/* enforce stacking: only the last enabled patch can be disabled */
if (!list_is_last(&patch->list, &klp_patches) &&
Expand All @@ -476,12 +451,8 @@ static int __klp_disable_patch(struct klp_patch *patch)
pr_notice("disabling patch '%s'\n", patch->mod->name);

for (obj = patch->objs; obj->funcs; obj++) {
if (obj->state != KLP_ENABLED)
continue;

ret = klp_disable_object(obj);
if (ret)
return ret;
if (obj->state == KLP_ENABLED)
klp_disable_object(obj);
}

patch->state = KLP_DISABLED;
Expand Down Expand Up @@ -931,18 +902,14 @@ static void klp_module_notify_going(struct klp_patch *patch,
{
struct module *pmod = patch->mod;
struct module *mod = obj->mod;
int ret;

if (patch->state == KLP_DISABLED)
goto disabled;

pr_notice("reverting patch '%s' on unloading module '%s'\n",
pmod->name, mod->name);

ret = klp_disable_object(obj);
if (ret)
pr_warn("failed to revert patch '%s' on module '%s' (%d)\n",
pmod->name, mod->name, ret);
klp_disable_object(obj);

disabled:
klp_free_object_loaded(obj);
Expand Down

0 comments on commit 0937e3b

Please sign in to comment.