kmod/core: protect kpatch_[un]register with mutex

Use a mutex in the register/unregister functions to protect changes to
kpatch_num_registered, kpatch_func_hash and calls to the ftrace
functions by other register/unregister invocations.
This commit is contained in:
Josh Poimboeuf 2014-03-19 10:01:29 -05:00
parent ae6fce2cd9
commit 37a756af58

View File

@ -48,6 +48,8 @@
#define KPATCH_HASH_BITS 8 #define KPATCH_HASH_BITS 8
DEFINE_HASHTABLE(kpatch_func_hash, KPATCH_HASH_BITS); DEFINE_HASHTABLE(kpatch_func_hash, KPATCH_HASH_BITS);
DEFINE_SEMAPHORE(kpatch_mutex);
static int kpatch_num_registered; static int kpatch_num_registered;
struct kpatch_backtrace_args { struct kpatch_backtrace_args {
@ -209,6 +211,8 @@ int kpatch_register(struct module *mod, struct kpatch_func *funcs,
.num_funcs = num_funcs, .num_funcs = num_funcs,
}; };
down(&kpatch_mutex);
for (i = 0; i < num_funcs; i++) { for (i = 0; i < num_funcs; i++) {
struct kpatch_func *func = &funcs[i]; struct kpatch_func *func = &funcs[i];
@ -225,7 +229,7 @@ int kpatch_register(struct module *mod, struct kpatch_func *funcs,
} }
/* Register the ftrace trampoline if it hasn't been done already. */ /* Register the ftrace trampoline if it hasn't been done already. */
if (!kpatch_num_registered++) { /* TODO atomic */ if (!kpatch_num_registered++) {
ret = register_ftrace_function(&kpatch_ftrace_ops); ret = register_ftrace_function(&kpatch_ftrace_ops);
if (ret) { if (ret) {
printk("kpatch: can't register ftrace function \n"); printk("kpatch: can't register ftrace function \n");
@ -252,6 +256,7 @@ int kpatch_register(struct module *mod, struct kpatch_func *funcs,
pr_notice("loaded patch module \"%s\"\n", mod->name); pr_notice("loaded patch module \"%s\"\n", mod->name);
out: out:
up(&kpatch_mutex);
return ret; return ret;
} }
EXPORT_SYMBOL(kpatch_register); EXPORT_SYMBOL(kpatch_register);
@ -265,6 +270,8 @@ int kpatch_unregister(struct module *mod, struct kpatch_func *funcs,
.num_funcs = num_funcs, .num_funcs = num_funcs,
}; };
down(&kpatch_mutex);
ret = stop_machine(kpatch_remove_patch, &args, NULL); ret = stop_machine(kpatch_remove_patch, &args, NULL);
if (ret) if (ret)
goto out; goto out;
@ -293,6 +300,7 @@ int kpatch_unregister(struct module *mod, struct kpatch_func *funcs,
pr_notice("unloaded patch module \"%s\"\n", mod->name); pr_notice("unloaded patch module \"%s\"\n", mod->name);
out: out:
up(&kpatch_mutex);
return ret; return ret;
} }
EXPORT_SYMBOL(kpatch_unregister); EXPORT_SYMBOL(kpatch_unregister);