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