mirror of
https://github.com/dynup/kpatch
synced 2024-12-26 23:32:04 +00:00
livepatch-patch-hook: add support for livepatch sympos
Support patching objects that have duplicated function names. This feature was introduced upstream in Linux v4.5. This patch appends the symbol position to the symbol structure when lookup_local_symbol is called. This pos variable is then used when creating the funcs and dynrelas sections. Finally, incorporate sympos into the livepatch patch hook only if the kernel version is greater than v4.5. In other cases the older format is used. Fixes: #493 Signed-off-by: Chris J Arges <chris.j.arges@canonical.com>
This commit is contained in:
parent
08f55afa0a
commit
b64ab2b5e4
@ -27,6 +27,7 @@ struct kpatch_patch_func {
|
||||
unsigned long new_size;
|
||||
unsigned long old_addr;
|
||||
unsigned long old_size;
|
||||
unsigned long sympos;
|
||||
char *name;
|
||||
char *objname;
|
||||
};
|
||||
@ -35,6 +36,7 @@ struct kpatch_patch_dynrela {
|
||||
unsigned long dest;
|
||||
unsigned long src;
|
||||
unsigned long type;
|
||||
unsigned long sympos;
|
||||
char *name;
|
||||
char *objname;
|
||||
int external;
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/version.h>
|
||||
|
||||
#include <linux/livepatch.h>
|
||||
|
||||
@ -237,7 +238,11 @@ static int __init patch_init(void)
|
||||
lfunc = &lfuncs[j];
|
||||
lfunc->old_name = func->kfunc->name;
|
||||
lfunc->new_func = (void *)func->kfunc->new_addr;
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 5, 0)
|
||||
lfunc->old_sympos = func->kfunc->sympos;
|
||||
#else
|
||||
lfunc->old_addr = func->kfunc->old_addr;
|
||||
#endif
|
||||
j++;
|
||||
}
|
||||
|
||||
@ -250,7 +255,11 @@ static int __init patch_init(void)
|
||||
list_for_each_entry(reloc, &object->relocs, list) {
|
||||
lreloc = &lrelocs[j];
|
||||
lreloc->loc = reloc->kdynrela->dest;
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 5, 0)
|
||||
lreloc->sympos = reloc->kdynrela->sympos;
|
||||
#else
|
||||
lreloc->val = reloc->kdynrela->src;
|
||||
#endif
|
||||
lreloc->type = reloc->kdynrela->type;
|
||||
lreloc->name = reloc->kdynrela->name;
|
||||
lreloc->addend = reloc->kdynrela->addend;
|
||||
|
@ -2539,6 +2539,7 @@ void kpatch_create_patches_sections(struct kpatch_elf *kelf,
|
||||
funcs[index].old_addr = result.value;
|
||||
funcs[index].old_size = result.size;
|
||||
funcs[index].new_size = sym->sym.st_size;
|
||||
funcs[index].sympos = result.pos;
|
||||
|
||||
/*
|
||||
* Add a relocation that will populate
|
||||
@ -2715,6 +2716,7 @@ void kpatch_create_dynamic_rela_sections(struct kpatch_elf *kelf,
|
||||
dynrelas[index].addend = rela->addend;
|
||||
dynrelas[index].type = rela->type;
|
||||
dynrelas[index].external = external;
|
||||
dynrelas[index].sympos = result.pos;
|
||||
|
||||
/* add rela to fill in dest field */
|
||||
ALLOC_LINK(dynrela, &relasec->relas);
|
||||
|
@ -148,6 +148,7 @@ int lookup_local_symbol(struct lookup_table *table, char *name, char *hint,
|
||||
{
|
||||
struct symbol *sym, *match = NULL;
|
||||
int i;
|
||||
unsigned long pos = 0;
|
||||
char *curfile = NULL;
|
||||
|
||||
memset(result, 0, sizeof(*result));
|
||||
@ -159,19 +160,30 @@ int lookup_local_symbol(struct lookup_table *table, char *name, char *hint,
|
||||
} else if (curfile)
|
||||
curfile = NULL; /* end hint file symbols */
|
||||
}
|
||||
if (!curfile)
|
||||
continue;
|
||||
if (sym->bind == STB_LOCAL && !strcmp(sym->name, name)) {
|
||||
if (match)
|
||||
/* dup file+symbol, unresolvable ambiguity */
|
||||
return 1;
|
||||
match = sym;
|
||||
if (sym->bind == STB_LOCAL) {
|
||||
if (sym->name && !strcmp(sym->name, name)) {
|
||||
/*
|
||||
* need to count any occurrence of the symbol
|
||||
* name, unless we've already found a match
|
||||
*/
|
||||
if (!match)
|
||||
pos++;
|
||||
|
||||
if (!curfile)
|
||||
continue;
|
||||
|
||||
if (match)
|
||||
/* dup file+symbol, unresolvable ambiguity */
|
||||
return 1;
|
||||
match = sym;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!match)
|
||||
return 1;
|
||||
|
||||
result->pos = pos;
|
||||
result->value = match->value;
|
||||
result->size = match->size;
|
||||
return 0;
|
||||
@ -189,6 +201,7 @@ int lookup_global_symbol(struct lookup_table *table, char *name,
|
||||
!strcmp(sym->name, name)) {
|
||||
result->value = sym->value;
|
||||
result->size = sym->size;
|
||||
result->pos = 0; /* always 0 for global symbols */
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -220,9 +233,9 @@ static void find_this(struct lookup_table *table, char *sym, char *hint)
|
||||
else
|
||||
lookup_global_symbol(table, sym, &result);
|
||||
|
||||
printf("%s %s w/ %s hint at 0x%016lx len %lu\n",
|
||||
printf("%s %s w/ %s hint at 0x%016lx len %lu pos %lu\n",
|
||||
hint ? "local" : "global", sym, hint ? hint : "no",
|
||||
result.value, result.size);
|
||||
result.value, result.size, result.pos);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
|
@ -6,6 +6,7 @@ struct lookup_table;
|
||||
struct lookup_result {
|
||||
unsigned long value;
|
||||
unsigned long size;
|
||||
unsigned long pos;
|
||||
};
|
||||
|
||||
struct lookup_table *lookup_open(char *path);
|
||||
|
Loading…
Reference in New Issue
Block a user