From bf86555e0691e3b428751fd75201f0ef851917eb Mon Sep 17 00:00:00 2001 From: Seth Jennings Date: Mon, 11 Aug 2014 14:24:14 -0500 Subject: [PATCH 1/3] add correlation and compare support for GROUP sections GROUP section are rare and are a mechanism in the ELF to indicated that certain groups of section must be included or excluded (stripped) together. It is valid to have more than one of these section with the same ".group" name. This currently messes up the section correlation code with correlates based solely on name. This commit adds additional correlation criteria for GROUP sections; namely, the section content must be the same. Changing of groups sections (i.e. reindexing of the section indexes the GROUP section includes in their section data) is not supported and will result in a "new/changed section not included" error. Signed-off-by: Seth Jennings --- kpatch-build/create-diff-object.c | 54 +++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/kpatch-build/create-diff-object.c b/kpatch-build/create-diff-object.c index 779db0a..e76edfe 100644 --- a/kpatch-build/create-diff-object.c +++ b/kpatch-build/create-diff-object.c @@ -101,6 +101,7 @@ struct section { enum status status; int include; int ignore; + int grouped; union { struct { /* if (is_rela_section()) */ struct section *base; @@ -681,6 +682,17 @@ void kpatch_correlate_sections(struct list_head *seclist1, struct list_head *sec list_for_each_entry(sec2, seclist2, list) { if (strcmp(sec1->name, sec2->name)) continue; + /* + * Group sections must match exactly to be correlated. + * Changed group sections are currently not supported. + */ + if (sec1->sh.sh_type == SHT_GROUP) { + if (sec1->data->d_size != sec2->data->d_size) + continue; + if (memcmp(sec1->data->d_buf, sec2->data->d_buf, + sec1->data->d_size)) + continue; + } sec1->twin = sec2; sec2->twin = sec1; /* set initial status, might change */ @@ -698,6 +710,11 @@ void kpatch_correlate_symbols(struct list_head *symlist1, struct list_head *syml list_for_each_entry(sym2, symlist2, list) { if (!strcmp(sym1->name, sym2->name) && sym1->type == sym2->type) { + /* group section symbols must have correlated sections */ + if (sym1->sec && + sym1->sec->sh.sh_type == SHT_GROUP && + sym1->sec->twin != sym2->sec) + continue; sym1->twin = sym2; sym2->twin = sym1; /* set initial status, might change */ @@ -742,6 +759,31 @@ void kpatch_check_program_headers(Elf *elf) DIFF_FATAL("ELF contains program header"); } + +void kpatch_mark_grouped_sections(struct kpatch_elf *kelf) +{ + struct section *groupsec, *sec; + unsigned int *data, *end; + + list_for_each_entry(groupsec, &kelf->sections, list) { + if (groupsec->sh.sh_type != SHT_GROUP) + continue; + data = groupsec->data->d_buf; + end = groupsec->data->d_buf + groupsec->data->d_size; + data++; /* skip first flag word (e.g. GRP_COMDAT) */ + while (data < end) { + sec = find_section_by_index(&kelf->sections, *data); + if (!sec) + ERROR("group section not found"); + sec->grouped = 1; + log_debug("marking section %s (%d) as grouped\n", + sec->name, sec->index); + data++; + } + } +} + + /* * When gcc makes compiler optimizations which affect a function's calling * interface, it mangles the function's name. For example, sysctl_print_dir is @@ -1066,6 +1108,17 @@ void kpatch_verify_patchability(struct kpatch_elf *kelf) errs++; } + if (sec->status == CHANGED && sec->grouped) { + log_normal("changed section %s is part of a section group\n", + sec->name); + errs++; + } + + if (sec->sh.sh_type == SHT_GROUP && sec->status == NEW) { + log_normal("new/changed group sections are not supported\n"); + errs++; + } + /* ensure we aren't including .data.* or .bss.* */ if (sec->include && (!strncmp(sec->name, ".data", 5) || @@ -2516,6 +2569,7 @@ int main(int argc, char *argv[]) kpatch_check_program_headers(kelf_base->elf); kpatch_check_program_headers(kelf_patched->elf); + kpatch_mark_grouped_sections(kelf_patched); kpatch_replace_sections_syms(kelf_base); kpatch_replace_sections_syms(kelf_patched); kpatch_rename_mangled_functions(kelf_base, kelf_patched); From a0e6dce9af06321c1deaefa53a297522dc5d3452 Mon Sep 17 00:00:00 2001 From: Seth Jennings Date: Mon, 11 Aug 2014 14:29:43 -0500 Subject: [PATCH 2/3] cleanup kpatch_correlate_symbols() This commit inverts some logic to reduce the max indentation Signed-off-by: Seth Jennings --- kpatch-build/create-diff-object.c | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/kpatch-build/create-diff-object.c b/kpatch-build/create-diff-object.c index e76edfe..314622e 100644 --- a/kpatch-build/create-diff-object.c +++ b/kpatch-build/create-diff-object.c @@ -708,19 +708,21 @@ void kpatch_correlate_symbols(struct list_head *symlist1, struct list_head *syml list_for_each_entry(sym1, symlist1, list) { list_for_each_entry(sym2, symlist2, list) { - if (!strcmp(sym1->name, sym2->name) && - sym1->type == sym2->type) { - /* group section symbols must have correlated sections */ - if (sym1->sec && - sym1->sec->sh.sh_type == SHT_GROUP && - sym1->sec->twin != sym2->sec) - continue; - sym1->twin = sym2; - sym2->twin = sym1; - /* set initial status, might change */ - sym1->status = sym2->status = SAME; - break; - } + if (strcmp(sym1->name, sym2->name) || + sym1->type != sym2->type) + continue; + + /* group section symbols must have correlated sections */ + if (sym1->sec && + sym1->sec->sh.sh_type == SHT_GROUP && + sym1->sec->twin != sym2->sec) + continue; + + sym1->twin = sym2; + sym2->twin = sym1; + /* set initial status, might change */ + sym1->status = sym2->status = SAME; + break; } } } From e1e694db4b89a61c2c6717d5ee7c300276550aa9 Mon Sep 17 00:00:00 2001 From: Seth Jennings Date: Mon, 11 Aug 2014 22:41:09 -0500 Subject: [PATCH 3/3] review fixups Signed-off-by: Seth Jennings --- kpatch-build/create-diff-object.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kpatch-build/create-diff-object.c b/kpatch-build/create-diff-object.c index 314622e..52d9e57 100644 --- a/kpatch-build/create-diff-object.c +++ b/kpatch-build/create-diff-object.c @@ -1110,7 +1110,7 @@ void kpatch_verify_patchability(struct kpatch_elf *kelf) errs++; } - if (sec->status == CHANGED && sec->grouped) { + if (sec->status != SAME && sec->grouped) { log_normal("changed section %s is part of a section group\n", sec->name); errs++;