kmod: add new kpatch_module struct

Put funcs, num_funcs, and mod in their own struct called kpatch_module.
This allows us to keep patch module specific variables in one place (and
we'll have more of these variables soon).
This commit is contained in:
Josh Poimboeuf 2014-04-21 11:29:01 -05:00
parent ff28767295
commit 2984b53d21
3 changed files with 53 additions and 59 deletions

View File

@ -53,8 +53,8 @@ DEFINE_SEMAPHORE(kpatch_mutex);
static int kpatch_num_registered; static int kpatch_num_registered;
struct kpatch_backtrace_args { struct kpatch_backtrace_args {
struct kpatch_func *funcs; struct kpatch_module *kpmod;
int num_funcs, ret; int ret;
}; };
enum { enum {
@ -88,14 +88,14 @@ void kpatch_backtrace_address_verify(void *data, unsigned long address,
int reliable) int reliable)
{ {
struct kpatch_backtrace_args *args = data; struct kpatch_backtrace_args *args = data;
struct kpatch_func *funcs = args->funcs; struct kpatch_module *kpmod = args->kpmod;
int i, num_funcs = args->num_funcs; int i;
if (args->ret) if (args->ret)
return; return;
for (i = 0; i < num_funcs; i++) { for (i = 0; i < kpmod->num_funcs; i++) {
struct kpatch_func *func = &funcs[i]; struct kpatch_func *func = &kpmod->funcs[i];
if (address >= func->old_addr && if (address >= func->old_addr &&
address < func->old_addr + func->old_size) { address < func->old_addr + func->old_size) {
@ -124,15 +124,13 @@ struct stacktrace_ops kpatch_backtrace_ops = {
* *
* This function is called from stop_machine() context. * This function is called from stop_machine() context.
*/ */
static int kpatch_verify_activeness_safety(struct kpatch_func *funcs, static int kpatch_verify_activeness_safety(struct kpatch_module *kpmod)
int num_funcs)
{ {
struct task_struct *g, *t; struct task_struct *g, *t;
int ret = 0; int ret = 0;
struct kpatch_backtrace_args args = { struct kpatch_backtrace_args args = {
.funcs = funcs, .kpmod = kpmod,
.num_funcs = num_funcs,
.ret = 0 .ret = 0
}; };
@ -149,20 +147,15 @@ out:
return ret; return ret;
} }
struct kpatch_stop_machine_args {
struct kpatch_func *funcs;
int num_funcs;
};
/* Called from stop_machine */ /* Called from stop_machine */
static int kpatch_apply_patch(void *data) static int kpatch_apply_patch(void *data)
{ {
struct kpatch_stop_machine_args *args = data; struct kpatch_module *kpmod = data;
struct kpatch_func *funcs = args->funcs; struct kpatch_func *funcs = kpmod->funcs;
int num_funcs = args->num_funcs; int num_funcs = kpmod->num_funcs;
int i, ret; int i, ret;
ret = kpatch_verify_activeness_safety(funcs, num_funcs); ret = kpatch_verify_activeness_safety(kpmod);
if (ret) if (ret)
goto out; goto out;
@ -194,12 +187,12 @@ out:
/* Called from stop_machine */ /* Called from stop_machine */
static int kpatch_remove_patch(void *data) static int kpatch_remove_patch(void *data)
{ {
struct kpatch_stop_machine_args *args = data; struct kpatch_module *kpmod = data;
struct kpatch_func *funcs = args->funcs; struct kpatch_func *funcs = kpmod->funcs;
int num_funcs = args->num_funcs; int num_funcs = kpmod->num_funcs;
int ret, i; int ret, i;
ret = kpatch_verify_activeness_safety(funcs, num_funcs); ret = kpatch_verify_activeness_safety(kpmod);
if (ret) if (ret)
goto out; goto out;
@ -343,21 +336,20 @@ static int kpatch_remove_funcs_from_filter(struct kpatch_func *funcs,
return ret; return ret;
} }
int kpatch_register(struct module *mod, struct kpatch_func *funcs, int kpatch_register(struct kpatch_module *kpmod)
int num_funcs)
{ {
int ret, i; int ret, i;
struct kpatch_stop_machine_args args = { struct kpatch_func *funcs = kpmod->funcs;
.funcs = funcs, int num_funcs = kpmod->num_funcs;
.num_funcs = num_funcs,
}; if (!kpmod->mod || !funcs || !num_funcs)
return -EINVAL;
down(&kpatch_mutex); 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];
func->mod = mod;
func->updating = true; func->updating = true;
/* /*
@ -399,7 +391,7 @@ int kpatch_register(struct module *mod, struct kpatch_func *funcs,
* Idle the CPUs, verify activeness safety, and atomically make the new * Idle the CPUs, verify activeness safety, and atomically make the new
* functions visible to the trampoline. * functions visible to the trampoline.
*/ */
ret = stop_machine(kpatch_apply_patch, &args, NULL); ret = stop_machine(kpatch_apply_patch, kpmod, NULL);
if (ret) { if (ret) {
/* /*
* This synchronize_rcu is to ensure any other kpatch_get_func * This synchronize_rcu is to ensure any other kpatch_get_func
@ -414,7 +406,7 @@ int kpatch_register(struct module *mod, struct kpatch_func *funcs,
pr_notice_once("tainting kernel with TAINT_USER\n"); pr_notice_once("tainting kernel with TAINT_USER\n");
add_taint(TAINT_USER, LOCKDEP_STILL_OK); add_taint(TAINT_USER, LOCKDEP_STILL_OK);
pr_notice("loaded patch module \"%s\"\n", mod->name); pr_notice("loaded patch module \"%s\"\n", kpmod->mod->name);
out: out:
atomic_set(&kpatch_operation, KPATCH_OP_NONE); atomic_set(&kpatch_operation, KPATCH_OP_NONE);
@ -436,14 +428,11 @@ err_rollback:
} }
EXPORT_SYMBOL(kpatch_register); EXPORT_SYMBOL(kpatch_register);
int kpatch_unregister(struct module *mod, struct kpatch_func *funcs, int kpatch_unregister(struct kpatch_module *kpmod)
int num_funcs)
{ {
struct kpatch_func *funcs = kpmod->funcs;
int num_funcs = kpmod->num_funcs;
int i, ret; int i, ret;
struct kpatch_stop_machine_args args = {
.funcs = funcs,
.num_funcs = num_funcs,
};
down(&kpatch_mutex); down(&kpatch_mutex);
@ -458,7 +447,7 @@ int kpatch_unregister(struct module *mod, struct kpatch_func *funcs,
for (i = 0; i < num_funcs; i++) for (i = 0; i < num_funcs; i++)
funcs[i].updating = true; funcs[i].updating = true;
ret = stop_machine(kpatch_remove_patch, &args, NULL); ret = stop_machine(kpatch_remove_patch, kpmod, NULL);
if (ret) if (ret)
goto out; goto out;
@ -482,7 +471,7 @@ int kpatch_unregister(struct module *mod, struct kpatch_func *funcs,
if (ret) if (ret)
goto out; goto out;
pr_notice("unloaded patch module \"%s\"\n", mod->name); pr_notice("unloaded patch module \"%s\"\n", kpmod->mod->name);
out: out:
atomic_set(&kpatch_operation, KPATCH_OP_NONE); atomic_set(&kpatch_operation, KPATCH_OP_NONE);

View File

@ -31,14 +31,17 @@ struct kpatch_func {
unsigned long new_addr; unsigned long new_addr;
unsigned long old_addr; unsigned long old_addr;
unsigned long old_size; unsigned long old_size;
struct module *mod;
struct hlist_node node; struct hlist_node node;
bool updating; bool updating;
}; };
extern int kpatch_register(struct module *mod, struct kpatch_func *funcs, struct kpatch_module {
int num_funcs); struct module *mod;
extern int kpatch_unregister(struct module *mod, struct kpatch_func *funcs, struct kpatch_func *funcs;
int num_funcs); int num_funcs;
};
extern int kpatch_register(struct kpatch_module *kpmod);
extern int kpatch_unregister(struct kpatch_module *kpmod);
#endif /* _KPATCH_H_ */ #endif /* _KPATCH_H_ */

View File

@ -27,8 +27,7 @@
extern char __kpatch_patches, __kpatch_patches_end; extern char __kpatch_patches, __kpatch_patches_end;
static struct kpatch_func *funcs; static struct kpatch_module kpmod;
static int num_funcs;
static int __init patch_init(void) static int __init patch_init(void)
{ {
@ -36,26 +35,29 @@ static int __init patch_init(void)
int i, ret; int i, ret;
patches = (struct kpatch_patch *)&__kpatch_patches; patches = (struct kpatch_patch *)&__kpatch_patches;
num_funcs = (&__kpatch_patches_end - &__kpatch_patches) /
sizeof(*patches); kpmod.mod = THIS_MODULE;
funcs = kmalloc(num_funcs * sizeof(*funcs), GFP_KERNEL); kpmod.num_funcs = (&__kpatch_patches_end - &__kpatch_patches) /
if (!funcs) sizeof(*patches);
kpmod.funcs = kmalloc(kpmod.num_funcs * sizeof(struct kpatch_func),
GFP_KERNEL);
if (!kpmod.funcs)
return -ENOMEM; return -ENOMEM;
for (i = 0; i < num_funcs; i++) { for (i = 0; i < kpmod.num_funcs; i++) {
funcs[i].old_addr = patches[i].old_addr; kpmod.funcs[i].old_addr = patches[i].old_addr;
funcs[i].old_size = patches[i].old_size; kpmod.funcs[i].old_size = patches[i].old_size;
funcs[i].new_addr = patches[i].new_addr; kpmod.funcs[i].new_addr = patches[i].new_addr;
} }
ret = kpatch_register(THIS_MODULE, funcs, num_funcs); ret = kpatch_register(&kpmod);
if (ret) if (ret)
goto err_free; goto err_free;
return 0; return 0;
err_free: err_free:
kfree(funcs); kfree(kpmod.funcs);
return ret; return ret;
} }
@ -63,7 +65,7 @@ static void __exit patch_exit(void)
{ {
int ret; int ret;
ret = kpatch_unregister(THIS_MODULE, funcs, num_funcs); ret = kpatch_unregister(&kpmod);
if (ret) { if (ret) {
/* /*
* TODO: If this happens, we're screwed. We need a way to * TODO: If this happens, we're screwed. We need a way to
@ -77,7 +79,7 @@ static void __exit patch_exit(void)
panic("kpatch_unregister failed: %d", ret); panic("kpatch_unregister failed: %d", ret);
} }
kfree(funcs); kfree(kpmod.funcs);
} }
module_init(patch_init); module_init(patch_init);