fix activeness safety check when unpatching

When unpatching, the activeness safety logic should check for the new
function on the stack, not the old one.

Fixes #64.
This commit is contained in:
Josh Poimboeuf 2014-04-21 11:49:58 -05:00
parent 48cc3a409e
commit f3f39c0587
5 changed files with 28 additions and 5 deletions

View File

@ -118,12 +118,24 @@ void kpatch_backtrace_address_verify(void *data, unsigned long address,
return;
for (i = 0; i < kpmod->num_funcs; i++) {
struct kpatch_func *func = &kpmod->funcs[i];
unsigned long func_addr, func_size;
struct kpatch_func *func, *active_func;
if (address >= func->old_addr &&
address < func->old_addr + func->old_size) {
func = &kpmod->funcs[i];
active_func = kpatch_get_func(func->old_addr);
if (!active_func) {
/* patching an unpatched func */
func_addr = func->old_addr;
func_size = func->old_size;
} else {
/* repatching or unpatching */
func_addr = active_func->new_addr;
func_size = active_func->new_size;
}
if (address >= func_addr && address < func_addr + func_size) {
pr_err("activeness safety check failed for function "
"at address 0x%lx\n", func->old_addr);
"at address 0x%lx\n", func_addr);
args->ret = -EBUSY;
return;
}

View File

@ -29,6 +29,7 @@
struct kpatch_func {
unsigned long new_addr;
unsigned long new_size;
unsigned long old_addr;
unsigned long old_size;
struct hlist_node node;

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2013 Josh Poimboeuf <jpoimboe@redhat.com>
* Copyright (C) 2013-2014 Josh Poimboeuf <jpoimboe@redhat.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -48,6 +48,7 @@ static int __init patch_init(void)
kpmod.funcs[i].old_addr = patches[i].old_addr;
kpmod.funcs[i].old_size = patches[i].old_size;
kpmod.funcs[i].new_addr = patches[i].new_addr;
kpmod.funcs[i].new_size = patches[i].new_size;
}
ret = kpatch_register(&kpmod);

View File

@ -26,6 +26,7 @@
struct kpatch_patch {
unsigned long new_addr;
unsigned long new_size;
unsigned long old_addr;
unsigned long old_size;
};

View File

@ -315,10 +315,18 @@ int main(int argc, char **argv)
for_each_sym(&symlist, cur) {
if (cur->action != PATCH)
continue;
patches_data[i].old_addr = cur->vm_addr;
patches_data[i].old_size = cur->vm_len;
patches_data[i].new_size = cur->sym.st_size;
/*
* Use a relocation to set patches_data[i].new_addr at module
* loading time.
*/
relas_data[i].r_offset = i * sizeof(struct kpatch_patch);
relas_data[i].r_info = GELF_R_INFO(cur->index, R_X86_64_64);
i++;
}