support for gcc static local variable renaming

gcc renames static local variables by appending a period and a number.
For example, __key could be renamed to __key.31452.  Unfortunately this
number can arbitrarily change.  Try to rename the patched version of the
symbol to match the base version and then correlate them.

Fixes #313.
This commit is contained in:
Josh Poimboeuf 2014-07-24 12:40:54 -05:00
parent 402911b949
commit 9c3c9b0c0a
2 changed files with 122 additions and 0 deletions

View File

@ -764,6 +764,101 @@ void kpatch_rename_mangled_functions(struct kpatch_elf *base,
}
}
/*
* gcc renames static local variables by appending a period and a number. For
* example, __key could be renamed to __key.31452. Unfortunately this number
* can arbitrarily change. Try to rename the patched version of the symbol to
* match the base version and then correlate them.
*/
void kpatch_correlate_static_local_variables(struct kpatch_elf *base,
struct kpatch_elf *patched)
{
struct symbol *sym, *basesym;
struct section *tmpsec, *sec;
struct rela *rela;
int prefixlen;
char *dot;
list_for_each_entry(sym, &patched->symbols, list) {
if (sym->type != STT_OBJECT || sym->bind != STB_LOCAL ||
sym->twin)
continue;
dot = strchr(sym->name, '.');
if (!dot)
continue;
prefixlen = dot - sym->name;
if (sym->name[prefixlen+1] < '0' ||
sym->name[prefixlen+1] > '9')
continue;
/* find the patched function which uses the static variable */
sec = NULL;
list_for_each_entry(tmpsec, &patched->sections, list) {
if (!is_rela_section(tmpsec) ||
is_debug_section(tmpsec))
continue;
list_for_each_entry(rela, &tmpsec->relas, list) {
if (rela->sym != sym)
continue;
if (sec)
ERROR("static local variable %s used by two functions",
sym->name);
sec = tmpsec;
break;
}
}
if (!sec)
ERROR("static local variable %s not used", sym->name);
if (!sec->twin)
continue;
/*
* Ensure there are no other orphaned static variables with the
* same prefix in the function. This is possible if the
* variables are in different scopes (using C braces).
*/
list_for_each_entry(rela, &sec->relas, list) {
if (rela->sym == sym || rela->sym->twin)
continue;
if (!strncmp(rela->sym->name, sym->name, prefixlen))
ERROR("found another static local variable matching %s in patched %s",
sym->name, sec->name);
}
/* find the base object's corresponding variable */
basesym = NULL;
list_for_each_entry(rela, &sec->twin->relas, list) {
if (rela->sym->twin)
continue;
if (strncmp(rela->sym->name, sym->name, prefixlen))
continue;
if (basesym)
ERROR("found two static local variables matching %s in orig %s",
sym->name, sec->name);
basesym = rela->sym;
}
if (!basesym)
continue;
if (sym != sym->sec->sym)
ERROR("expected bundled section for %s", sym->name);
if (basesym != basesym->sec->sym)
ERROR("expected bundled section for %s",basesym->name);
log_debug("renaming and correlating %s to %s\n",
sym->name, basesym->name);
sym->name = strdup(basesym->name);
sym->twin = basesym;
basesym->twin = sym;
sym->sec->twin = basesym->sec;
basesym->sec->twin = sym->sec;
sym->status = basesym->status = SAME;
}
}
void kpatch_correlate_elfs(struct kpatch_elf *kelf1, struct kpatch_elf *kelf2)
{
kpatch_correlate_sections(&kelf1->sections, &kelf2->sections);
@ -2323,6 +2418,7 @@ int main(int argc, char *argv[])
kpatch_rename_mangled_functions(kelf_base, kelf_patched);
kpatch_correlate_elfs(kelf_base, kelf_patched);
kpatch_correlate_static_local_variables(kelf_base, kelf_patched);
/*
* After this point, we don't care about kelf_base anymore.

View File

@ -0,0 +1,26 @@
Index: src/arch/x86/kernel/ldt.c
===================================================================
--- src.orig/arch/x86/kernel/ldt.c
+++ src/arch/x86/kernel/ldt.c
@@ -100,6 +100,12 @@ static inline int copy_ldt(mm_context_t
return 0;
}
+void hi_there(void)
+{
+ if (!jiffies)
+ printk("hi there\n");
+}
+
/*
* we do not have to muck with descriptors here, that is
* done in switch_mm() as needed.
@@ -109,6 +115,8 @@ int init_new_context(struct task_struct
struct mm_struct *old_mm;
int retval = 0;
+ hi_there();
+
mutex_init(&mm->context.lock);
mm->context.size = 0;
old_mm = current->mm;