mirror of https://github.com/dynup/kpatch
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:
parent
ff28767295
commit
2984b53d21
|
@ -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);
|
||||||
|
|
|
@ -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_ */
|
||||||
|
|
|
@ -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) /
|
|
||||||
|
kpmod.mod = THIS_MODULE;
|
||||||
|
kpmod.num_funcs = (&__kpatch_patches_end - &__kpatch_patches) /
|
||||||
sizeof(*patches);
|
sizeof(*patches);
|
||||||
funcs = kmalloc(num_funcs * sizeof(*funcs), GFP_KERNEL);
|
kpmod.funcs = kmalloc(kpmod.num_funcs * sizeof(struct kpatch_func),
|
||||||
if (!funcs)
|
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);
|
||||||
|
|
Loading…
Reference in New Issue