From 13d61012f9b225f2b1749a3de9f0dec66d584a27 Mon Sep 17 00:00:00 2001 From: Ross Lagerwall Date: Thu, 10 Nov 2016 14:04:26 +0000 Subject: [PATCH] create-diff-object: Update fixup offsets in .rela__ex_table When pruning entries from the fixup table, update the offsets in .rela__ex_table otherwise the relas might point to the wrong fixup entry or even out of the .fixup section. Fixes #615. Signed-off-by: Ross Lagerwall --- kpatch-build/create-diff-object.c | 40 +++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/kpatch-build/create-diff-object.c b/kpatch-build/create-diff-object.c index 6c27ba0..d309468 100644 --- a/kpatch-build/create-diff-object.c +++ b/kpatch-build/create-diff-object.c @@ -1490,6 +1490,31 @@ int should_keep_rela_group(struct section *sec, int start, int size) return found; } +/* + * When updating .fixup, the corresponding addends in .ex_table need to be + * updated too. Stash the result in rela.r_addend so that the calculation in + * fixup_group_size() is not affected. + */ +void kpatch_update_ex_table_addend(struct kpatch_elf *kelf, + struct special_section *special, + int src_offset, int dest_offset, + int group_size) +{ + struct rela *rela; + struct section *sec; + + sec = find_section_by_name(&kelf->sections, ".rela__ex_table"); + if (!sec) + ERROR("missing .rela__ex_table section"); + + list_for_each_entry(rela, &sec->relas, list) { + if (!strcmp(rela->sym->name, ".fixup") && + rela->addend >= src_offset && + rela->addend < src_offset + group_size) + rela->rela.r_addend = rela->addend - (src_offset - dest_offset); + } +} + void kpatch_regenerate_special_section(struct kpatch_elf *kelf, struct special_section *special, struct section *sec) @@ -1506,6 +1531,14 @@ void kpatch_regenerate_special_section(struct kpatch_elf *kelf, if (!dest) ERROR("malloc"); + /* Restore the stashed r_addend from kpatch_update_ex_table_addend. */ + if (!strcmp(special->name, "__ex_table")) { + list_for_each_entry(rela, &sec->relas, list) { + if (!strcmp(rela->sym->name, ".fixup")) + rela->addend = rela->rela.r_addend; + } + } + group_size = 0; src_offset = 0; dest_offset = 0; @@ -1533,6 +1566,13 @@ void kpatch_regenerate_special_section(struct kpatch_elf *kelf, rela->rela.r_offset = rela->offset; rela->sym->include = 1; + + + if (!strcmp(special->name, ".fixup")) + kpatch_update_ex_table_addend(kelf, special, + src_offset, + dest_offset, + group_size); } }