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:
Chris J Arges 2016-02-11 11:27:12 -06:00
parent 08f55afa0a
commit b64ab2b5e4
5 changed files with 36 additions and 9 deletions

View File

@ -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;

View File

@ -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;

View File

@ -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);

View File

@ -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)

View File

@ -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);