From 8ac20f5475fd23e0068d90e9c3cad5c9007ab1e7 Mon Sep 17 00:00:00 2001 From: Seth Jennings Date: Thu, 24 Jul 2014 14:54:20 -0500 Subject: [PATCH] add KPATCH_IGNORE_SECTION support This macro is for ignoring sections that may change as a side effect of another change or might be a non-bundlable section; that is one that does not honor -ffunction-section and create a one-to-one relation from function symbol to section. Signed-off-by: Seth Jennings --- kmod/patch/kpatch-macros.h | 11 +++++++ kpatch-build/create-diff-object.c | 53 ++++++++++++++++++++++++++++++- 2 files changed, 63 insertions(+), 1 deletion(-) diff --git a/kmod/patch/kpatch-macros.h b/kmod/patch/kpatch-macros.h index cc8f842..9058b59 100644 --- a/kmod/patch/kpatch-macros.h +++ b/kmod/patch/kpatch-macros.h @@ -17,6 +17,17 @@ struct kpatch_unload { char *objname; /* filled in by create-diff-object */ }; +/* + * KPATCH_IGNORE_SECTION macro + * + * This macro is for ignoring sections that may change as a side effect of + * another change or might be a non-bundlable section; that is one that does + * not honor -ffunction-section and create a one-to-one relation from function + * symbol to section. + */ +#define KPATCH_IGNORE_SECTION(_sec) \ + char *__UNIQUE_ID(kpatch_ignore_section_) __section(.kpatch.ignore.sections) = _sec; + /* * KPATCH_IGNORE_FUNCTION macro * diff --git a/kpatch-build/create-diff-object.c b/kpatch-build/create-diff-object.c index 73dfd87..77c81dc 100644 --- a/kpatch-build/create-diff-object.c +++ b/kpatch-build/create-diff-object.c @@ -620,11 +620,15 @@ void kpatch_compare_correlated_symbol(struct symbol *sym) if (sym1->sym.st_info != sym2->sym.st_info || sym1->sym.st_other != sym2->sym.st_other || - (sym1->sec && sym2->sec && sym1->sec->twin != sym2->sec) || (sym1->sec && !sym2->sec) || (sym2->sec && !sym1->sec)) DIFF_FATAL("symbol info mismatch: %s", sym1->name); + if (sym1->sec && sym2->sec && sym1->sec->twin != sym2->sec) { + log_normal("NOTICE: symbol %s has changed sections\n", sym1->name); + sym1->status = CHANGED; + } + if (sym1->type == STT_OBJECT && sym1->sym.st_size != sym2->sym.st_size) DIFF_FATAL("object size mismatch: %s", sym1->name); @@ -1484,6 +1488,52 @@ void kpatch_include_debug_sections(struct kpatch_elf *kelf) } } +void kpatch_mark_ignored_sections_same(struct kpatch_elf *kelf) +{ + struct section *sec, *strsec, *ignoresec; + struct symbol *sym; + struct rela *rela; + char *name; + + sec = find_section_by_name(&kelf->sections, ".kpatch.ignore.sections"); + if (!sec) + return; + + list_for_each_entry(rela, &sec->rela->relas, list) { + strsec = rela->sym->sec; + strsec->status = CHANGED; + /* + * Include the string section here. This is because the + * KPATCH_IGNORE_SECTION() macro is passed a literal string + * by the patch author, resulting in a change to the string + * section. If we don't include it, then we will potentially + * get a "changed section not included" error in + * kpatch_verify_patchability() if not other function based change + * also changes the string section. We could try to exclude each + * literal string added to the section by KPATCH_IGNORE_SECTION() + * from the section data comparison, but this is a simpler way. + */ + strsec->include = 1; + name = strsec->data->d_buf + rela->addend; + ignoresec = find_section_by_name(&kelf->sections, name); + if (!ignoresec) + ERROR("expected ignored section"); + log_normal("ignoring section %s\n", name); + if (ignoresec->status != CHANGED) + ERROR("no change detected in ignored section %s\n", ignoresec->name); + ignoresec->status = SAME; + if (ignoresec->secsym) + ignoresec->secsym->status = SAME; + if (ignoresec->rela) + ignoresec->rela->status = SAME; + list_for_each_entry(sym, &kelf->symbols, list) { + if (sym->sec != sec) + continue; + sym->status = SAME; + } + } +} + void kpatch_mark_ignored_functions_same(struct kpatch_elf *kelf) { struct section *sec; @@ -2436,6 +2486,7 @@ int main(int argc, char *argv[]) kpatch_elf_free(kelf_base); kpatch_mark_ignored_functions_same(kelf_patched); + kpatch_mark_ignored_sections_same(kelf_patched); kpatch_process_special_sections(kelf_patched);