From f1ad9d71e677ae94de4b9efeb137ad34a7d10e6a Mon Sep 17 00:00:00 2001
From: Pete Swain <swine@google.com>
Date: Fri, 31 May 2024 15:17:46 -0700
Subject: [PATCH 100/118] create-diff-object: avoid reloc-type collisions on
elf.h constants
The elf.h reloc-type constants are not unique across archs, for example:
#define R_PPC64_REL24 10 /* PC relative 26 bit */
#define R_X86_64_32 10 /* Direct 32 bit zero extended */
so to avoid any unexpected aliasing, guard all R_arch_type refs with a
check on kelf->arch, or a global default arch set from the first elf
encountered.
Closes: #1356 ("Do we need more robust archeticture protection")
Signed-off-by: Pete Swain <swine@google.com>
Signed-off-by: Mihails Strasuns <mstrasun@amazon.com>
Signed-off-by: Joe Lawrence <joe.lawrence@redhat.com>
---
kpatch-build/create-diff-object.c | 77 ++++++++++++++++++-----------
kpatch-build/create-kpatch-module.c | 3 ++
kpatch-build/kpatch-elf.c | 24 ++++++++-
kpatch-build/kpatch-elf.h | 3 ++
4 files changed, 77 insertions(+), 30 deletions(-)
--- a/kpatch-build/create-diff-object.c
+++ b/kpatch-build/create-diff-object.c
@@ -215,6 +215,8 @@ static bool is_gcc6_localentry_bundled_s
*/
static struct rela *toc_rela(const struct rela *rela)
{
+ if (!is_arch(PPC64))
+ return (struct rela *)rela;
if (rela->type != R_PPC64_TOC16_HA &&
rela->type != R_PPC64_TOC16_LO_DS)
return (struct rela *)rela;
@@ -1623,7 +1625,7 @@ static void kpatch_replace_sections_syms
if (is_text_section(relasec->base) &&
!is_text_section(sym->sec) &&
- rela->type == R_X86_64_32S &&
+ is_arch(X86_64) && rela->type == R_X86_64_32S &&
rela->addend == (long)sym->sec->sh.sh_size &&
end == (long)sym->sec->sh.sh_size) {
@@ -3241,12 +3243,23 @@ static int function_ptr_rela(const struc
{
const struct rela *rela_toc = toc_rela(rela);
+ switch (def_arch()) {
+ case PPC64:
+ if (rela->type != R_PPC64_TOC16_HA &&
+ rela->type != R_PPC64_TOC16_LO_DS)
+ return false;
+ break;
+ case X86_64:
+ if (rela->type != R_X86_64_32S)
+ return false;
+ break;
+ default:
+ break;
+ }
+
return (rela_toc && rela_toc->sym->type == STT_FUNC &&
!rela_toc->sym->parent &&
- rela_toc->addend == (int)rela_toc->sym->sym.st_value &&
- (rela->type == R_X86_64_32S ||
- rela->type == R_PPC64_TOC16_HA ||
- rela->type == R_PPC64_TOC16_LO_DS));
+ rela_toc->addend == (int)rela_toc->sym->sym.st_value);
}
static bool need_klp_reloc(struct kpatch_elf *kelf, struct lookup_table *table,
@@ -3261,32 +3274,38 @@ static bool need_klp_reloc(struct kpatch
* These references are treated specially by the module loader and
* should never be converted to klp relocations.
*/
- if (rela->type == R_PPC64_REL16_HA || rela->type == R_PPC64_REL16_LO ||
- rela->type == R_PPC64_ENTRY)
- return false;
+ switch (kelf->arch) {
+ case PPC64:
+ if (rela->type == R_PPC64_REL16_HA || rela->type == R_PPC64_REL16_LO ||
+ rela->type == R_PPC64_ENTRY)
+ return false;
- /* v5.13+ kernels use relative jump labels */
- if (rela->type == R_PPC64_REL64 && strcmp(relasec->name, ".rela__jump_table"))
- return false;
+ /* v5.13+ kernels use relative jump labels */
+ if (rela->type == R_PPC64_REL64 && strcmp(relasec->name, ".rela__jump_table"))
+ return false;
- /*
- * On powerpc, the function prologue generated by GCC 6 has the
- * sequence:
- *
- * .globl my_func
- * .type my_func, @function
- * .quad .TOC.-my_func
- * my_func:
- * .reloc ., R_PPC64_ENTRY ; optional
- * ld r2,-8(r12)
- * add r2,r2,r12
- * .localentry my_func, .-my_func
- *
- * The R_PPC64_ENTRY is optional and its symbol might have an empty
- * name. Leave it as a normal rela.
- */
- if (rela->type == R_PPC64_ENTRY)
- return false;
+ /*
+ * On powerpc, the function prologue generated by GCC 6 has the
+ * sequence:
+ *
+ * .globl my_func
+ * .type my_func, @function
+ * .quad .TOC.-my_func
+ * my_func:
+ * .reloc ., R_PPC64_ENTRY ; optional
+ * ld r2,-8(r12)
+ * add r2,r2,r12
+ * .localentry my_func, .-my_func
+ *
+ * The R_PPC64_ENTRY is optional and its symbol might have an empty
+ * name. Leave it as a normal rela.
+ */
+ if (rela->type == R_PPC64_ENTRY)
+ return false;
+ break;
+ default:
+ break;
+ }
/*
* Allow references to core module symbols to remain as normal
--- a/kpatch-build/create-kpatch-module.c
+++ b/kpatch-build/create-kpatch-module.c
@@ -58,6 +58,9 @@ static void create_dynamic_rela_sections
dynsec = create_section_pair(kelf, ".kpatch.dynrelas", sizeof(*dynrelas), nr);
dynrelas = dynsec->data->d_buf;
+ if (kelf->arch != X86_64)
+ return;
+
for (index = 0; index < nr; index++) {
offset = index * (unsigned int)sizeof(*krelas);
--- a/kpatch-build/kpatch-elf.c
+++ b/kpatch-build/kpatch-elf.c
@@ -38,6 +38,26 @@
* Helper functions
******************/
+static enum architecture current_arch;
+
+enum architecture def_arch(void)
+{
+ return current_arch;
+}
+
+bool is_arch(enum architecture arch)
+{
+ return current_arch == arch;
+}
+
+void set_arch(enum architecture arch)
+{
+ if (!arch || (current_arch && arch != current_arch))
+ ERROR("inconsistent ELF arch: setting %d but already %d",
+ arch, current_arch);
+ current_arch = arch;
+}
+
char *status_str(enum status status)
{
switch(status) {
@@ -594,8 +614,10 @@ struct kpatch_elf *kpatch_elf_open(const
kelf->arch = S390;
break;
default:
- ERROR("Unsupported target architecture");
+ ERROR("Unsupported target architecture: e_machine %x",
+ ehdr.e_machine);
}
+ set_arch(kelf->arch);
kpatch_create_section_list(kelf);
kpatch_create_symbol_list(kelf);
--- a/kpatch-build/kpatch-elf.h
+++ b/kpatch-build/kpatch-elf.h
@@ -159,6 +159,9 @@ int offset_of_string(struct list_head *l
long rela_target_offset(struct kpatch_elf *kelf, struct section *relasec,
struct rela *rela);
unsigned int insn_length(struct kpatch_elf *kelf, void *addr);
+enum architecture def_arch(void);
+void set_arch(enum architecture);
+bool is_arch(enum architecture);
#ifndef R_PPC64_ENTRY
#define R_PPC64_ENTRY 118