Message ID | 20161124010837.18077-2-konrad@kernel.org (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
On 11/24/2016 01:08 AM, Konrad Rzeszutek Wilk wrote: > From: Ross Lagerwall <ross.lagerwall@citrix.com> > > 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. > > Signed-off-by: Ross Lagerwall <ross.lagerwall@citrix.com> > Signed-off-by: Konrad Rzeszutek Wilk <konrad@kernel.org> > --- > v2: Squashed fix from kpatch upstream > [see https://github.com/dynup/kpatch/pull/616] > --- > create-diff-object.c | 41 +++++++++++++++++++++++++++++++++++++++++ > 1 file changed, 41 insertions(+) > > diff --git a/create-diff-object.c b/create-diff-object.c > index 69bcd88..58f7c4c 100644 > --- a/create-diff-object.c > +++ b/create-diff-object.c > @@ -1057,6 +1057,34 @@ static 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; > + > + if (strcmp(special->name, ".fixup")) > + return; As suggested by kpatch upstream, the code would be clearer if the above check is in kpatch_regenerate_special_section() rather than this function. I'll update and resend. > + > + 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); > + } > +} > + > static void kpatch_regenerate_special_section(struct kpatch_elf *kelf, > struct special_section *special, > struct section *sec) > @@ -1073,6 +1101,14 @@ static 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; > @@ -1100,6 +1136,11 @@ static void kpatch_regenerate_special_section(struct kpatch_elf *kelf, > rela->rela.r_offset = rela->offset; > > rela->sym->include = 1; > + > + kpatch_update_ex_table_addend(kelf, special, > + src_offset, > + dest_offset, > + group_size); > } > } > >
diff --git a/create-diff-object.c b/create-diff-object.c index 69bcd88..58f7c4c 100644 --- a/create-diff-object.c +++ b/create-diff-object.c @@ -1057,6 +1057,34 @@ static 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; + + if (strcmp(special->name, ".fixup")) + return; + + 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); + } +} + static void kpatch_regenerate_special_section(struct kpatch_elf *kelf, struct special_section *special, struct section *sec) @@ -1073,6 +1101,14 @@ static 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; @@ -1100,6 +1136,11 @@ static void kpatch_regenerate_special_section(struct kpatch_elf *kelf, rela->rela.r_offset = rela->offset; rela->sym->include = 1; + + kpatch_update_ex_table_addend(kelf, special, + src_offset, + dest_offset, + group_size); } }