From c61cb6776a3255e9f6578db89a1f1fcef3bb0e0a Mon Sep 17 00:00:00 2001 From: Kamalesh Babulal Date: Tue, 13 Mar 2018 13:39:31 +0530 Subject: [PATCH 1/4] create-diff-object: Add support for .toc constants .toc section entries are mostly place holder for relocation entries, specified in .rela.toc section. Sometimes, .toc section may have constants as entries. These constants are not reference to any symbols, but plain instructions mostly due to some arthimetics in the functions referring them. They are referred by the functions like normal .toc entries, these entries can not be resolved to any symbols. This patch creates a list of constants if available for .toc sections and compares them in rela_equal() to ensure their is no mismatch in the generated constants for original and patched .o files. Cc: Josh Poimboeuf Signed-off-by: Kamalesh Babulal --- kpatch-build/create-diff-object.c | 52 ++++++++++++++++++++++++++++--- 1 file changed, 48 insertions(+), 4 deletions(-) diff --git a/kpatch-build/create-diff-object.c b/kpatch-build/create-diff-object.c index 49d0aa9..2af7454 100644 --- a/kpatch-build/create-diff-object.c +++ b/kpatch-build/create-diff-object.c @@ -245,6 +245,7 @@ static int rela_equal(struct rela *rela1, struct rela *rela2) #ifdef __powerpc__ struct section *toc_relasec1, *toc_relasec2; struct rela *r_toc_relasec1, *r_toc_relasec2; + unsigned long toc_data1, toc_data2; #endif if (rela1->type != rela2->type || @@ -288,16 +289,59 @@ static int rela_equal(struct rela *rela1, struct rela *rela2) ERROR("cannot find .rela.toc"); r_toc_relasec1 = find_rela_by_offset(toc_relasec1, rela1->addend); - if (!r_toc_relasec1) - ERROR(".toc entry not found %s + %x", rela1->sym->name, rela1->addend); + if (!r_toc_relasec1) { + /* + * .toc section entries are mostly place holder for relocation entries, specified + * in .rela.toc section. Sometimes, .toc section may have constants as entries. + * These constants are not reference to any symbols, but plain instructions mostly + * due to some arithmetics in the functions referring them. + * + * They are referred by the functions like normal .toc entries, these entries can + * not be resolved to any symbols. + * + * Disassembly of section .toc: + * + * 0000000000000000 <.toc>: + * ... + * 148: R_PPC64_ADDR64 .data.capacity_margin + * 150: 0b d7 a3 70 andi. r3,r5,55051 + * 154: 3d 0a d7 a3 lhz r30,2621(r23) + * 158: R_PPC64_ADDR64 sched_max_numa_distance + * + * Relocation section '.rela.toc' at offset 0xadac0 contains 160 entries: + * Offset Info Type Symbol's Value Symbol's Name + Addend + * ... + * 0000000000000148 0000009100000026 R_PPC64_ADDR64 0000000000000000 .data.capacity_margin + 0 + * 0000000000000158 000001a500000026 R_PPC64_ADDR64 0000000000000000 sched_max_numa_distance + 0 + * + * Relocation section '.rela.text.select_task_rq_fair' at offset 0x90e98 contains 37 entries: + * Offset Info Type Symbol's Value Symbol's Name + Addend + * ... + * 0000000000000498 000000c90000000a R_PPC64_REL24 0000000000000000 __update_load_avg_blocked_se.isra.0 + 0 + * 00000000000004a0 0000008800000032 R_PPC64_TOC16_HA 0000000000000000 .toc + 148 + * 00000000000004ac 0000008800000040 R_PPC64_TOC16_LO_DS 0000000000000000 .toc + 148 + * 0000000000000514 0000008800000032 R_PPC64_TOC16_HA 0000000000000000 .toc + 150 + * 000000000000051c 0000008800000040 R_PPC64_TOC16_LO_DS 0000000000000000 .toc + 150 + * 00000000000005e0 000001870000000a R_PPC64_REL24 0000000000000000 __bitmap_intersects + 0 + */ + memcpy(&toc_data1, rela1->sym->sec->data->d_buf + rela1->addend, sizeof(toc_data1)); + if (!toc_data1) + ERROR(".toc entry not found %s + %x", rela1->sym->name, rela1->addend); + } toc_relasec2 = rela2->sym->sec->rela; if (!toc_relasec2) ERROR("cannot find .rela.toc"); r_toc_relasec2 = find_rela_by_offset(toc_relasec2, rela2->addend); - if (!r_toc_relasec2) - ERROR(".toc entry not found %s + %x", rela2->sym->name, rela2->addend); + if (!r_toc_relasec2) { + memcpy(&toc_data2, rela2->sym->sec->data->d_buf + rela2->addend, sizeof(toc_data2)); + if (!toc_data2) + ERROR(".toc entry not found %s + %x", rela2->sym->name, rela2->addend); + } + + if (!r_toc_relasec1 && !r_toc_relasec2) + return toc_data1 == toc_data2; if (r_toc_relasec1->string) return r_toc_relasec2->string && From cac608a05a3a6afba7e93219c0530927ded59c4f Mon Sep 17 00:00:00 2001 From: Kamalesh Babulal Date: Mon, 12 Feb 2018 03:45:44 -0500 Subject: [PATCH 2/4] create-diff-object: Remove REL24 rela check in kpatch_replace_sections_syms Symbols with R_PPC64_REL24 relocation type are functions and it's currently assumed that all functions are replaced with their respective section symbols. There are function whose reference are not straight forward section symbol but section + offset. These function replacement should be handled more like bundled sections. Remove the check, which imposes the inital assumption. Suggested-by: Josh Poimboeuf Signed-off-by: Kamalesh Babulal --- kpatch-build/create-diff-object.c | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/kpatch-build/create-diff-object.c b/kpatch-build/create-diff-object.c index 2af7454..f1d460c 100644 --- a/kpatch-build/create-diff-object.c +++ b/kpatch-build/create-diff-object.c @@ -1168,17 +1168,6 @@ static void kpatch_replace_sections_syms(struct kpatch_elf *kelf) } #ifdef __powerpc__ - /* - * With -mcmodel=large, R_PPC64_REL24 is only used for - * functions. Assuming the function is bundled in a - * section, the section symbol should have been - * replaced with a text symbol already. Otherwise, - * bail out. If we hit this situation, more core is - * needed here to calculate the value of 'add_off'. - */ - if (rela->type == R_PPC64_REL24) - ERROR("Unexpected relocation type R_PPC64_REL24 for %s\n", rela->sym->name); - add_off = 0; #else if (rela->type == R_X86_64_PC32) { From 481d8c4bc267ea010cb235b42fd7353877c3f440 Mon Sep 17 00:00:00 2001 From: Kamalesh Babulal Date: Wed, 7 Mar 2018 13:03:18 +0530 Subject: [PATCH 3/4] create-diff-object: Support for __warned placed in .data.once With kernel commit b1fca27d384 ("kernel debug: support resetting WARN*_ONCE") the *_ONCE warnings are placed .data.once section. Including .data.once section is valid, so add an check in kpatch_verify_patchability() while checking for included invalid sections. Cc: Josh Poimboeuf Signed-off-by: Kamalesh Babulal --- kpatch-build/create-diff-object.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/kpatch-build/create-diff-object.c b/kpatch-build/create-diff-object.c index f1d460c..4a46267 100644 --- a/kpatch-build/create-diff-object.c +++ b/kpatch-build/create-diff-object.c @@ -1296,12 +1296,11 @@ static void kpatch_verify_patchability(struct kpatch_elf *kelf) /* * ensure we aren't including .data.* or .bss.* - * (.data.unlikely is ok b/c it only has __warned vars) + * (.data.unlikely and .data.once is ok b/c it only has __warned vars) */ if (sec->include && sec->status != NEW && - (!strncmp(sec->name, ".data", 5) || - !strncmp(sec->name, ".bss", 4)) && - strcmp(sec->name, ".data.unlikely")) { + (!strncmp(sec->name, ".data", 5) || !strncmp(sec->name, ".bss", 4)) && + (strcmp(sec->name, ".data.unlikely") && strcmp(sec->name, ".data.once"))) { log_normal("data section %s selected for inclusion\n", sec->name); errs++; From d651cd994cfb89a5aff2fdf7eafbe1be6c69225c Mon Sep 17 00:00:00 2001 From: Kamalesh Babulal Date: Wed, 7 Mar 2018 13:04:52 +0530 Subject: [PATCH 4/4] livepatch-patch-hook: Add upper bound kernel version for immediate flag Effective Kernel v4.16, the immediate flag is removed by upstream kernel commit d0807da78e11 ("livepatch: Remove immediate feature"). Add an upper bound kernel version check for inclusion of the immediate flag. Cc: Josh Poimboeuf Signed-off-by: Kamalesh Babulal --- kmod/patch/livepatch-patch-hook.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/kmod/patch/livepatch-patch-hook.c b/kmod/patch/livepatch-patch-hook.c index 6c89ff8..d27dc1a 100644 --- a/kmod/patch/livepatch-patch-hook.c +++ b/kmod/patch/livepatch-patch-hook.c @@ -47,7 +47,8 @@ #define HAVE_SYMPOS #endif -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0) || \ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0) && \ + LINUX_VERSION_CODE <= KERNEL_VERSION(4, 15, 0)) || \ defined(RHEL_RELEASE_CODE) #define HAVE_IMMEDIATE #endif