diff mbox series

core/init: Check BE elf version before assuming behaviour

Message ID 20191216045826.18231-1-jniethe5@gmail.com
State New
Headers show
Series core/init: Check BE elf version before assuming behaviour | expand

Checks

Context Check Description
snowpatch_ozlabs/apply_patch success Successfully applied on branch master (d75e82dbfbb9443efeb3f9a5921ac23605aab469)
snowpatch_ozlabs/snowpatch_job_snowpatch-skiboot success Test snowpatch/job/snowpatch-skiboot on branch master
snowpatch_ozlabs/snowpatch_job_snowpatch-skiboot-dco success Signed-off-by present

Commit Message

Jordan Niethe Dec. 16, 2019, 4:58 a.m. UTC
On big-endian, ELF ABIv1 is typically used. For ELF ABIv1, the entry
point is a function description. However, for ELF ABIv2 the entry points
directly at code. The big-endian loader assumes this behaviour
regardless of what ELF ABI version is set in the elf's flags. This can
result in entering at the wrong locations for non ABIv1 elfs. Add a
check for the ELF ABI version before assuming ABIv1 behaviour. If no
version is set, default to ELF ABIv2 behaviour - that is the entry
points directly to code.

Signed-off-by: Jordan Niethe <jniethe5@gmail.com>
---
 core/init.c   | 15 ++++++++++-----
 include/elf.h |  2 ++
 2 files changed, 12 insertions(+), 5 deletions(-)
diff mbox series

Patch

diff --git a/core/init.c b/core/init.c
index a7083456e5cb..ade91e07ba5b 100644
--- a/core/init.c
+++ b/core/init.c
@@ -183,11 +183,15 @@  static bool try_load_elf64(struct elf_hdr *header)
 		return false;
 	}
 
-	/* For the normal big-endian ELF ABI, the kernel entry points
-	 * to a function descriptor in the data section. Linux instead
-	 * has it point directly to code. Test whether it is pointing
+	/* On big-endian, typically ELF ABIv1 is used. With ELF ABIv1,
+	 * the kernel entry points to a function descriptor in the
+	 * data section. Linux instead has it point directly to code,
+	 * which is ELF ABIv2 behaviour.
+	 *
+	 * If the ELF ABIv1 flag is set, test whether it is pointing
 	 * into an executable section or not to figure this out. Default
-	 * to assuming it obeys the ABI.
+	 * to assuming it obeys the ABI version set in its flags. If no
+	 * ABI version is set, default to ELF ABIv2 behaviour.
 	 */
 	sh = (struct elf64_shdr *)(load_base + kh->e_shoff);
 	for (i = 0; i < kh->e_shnum; i++, sh++) {
@@ -196,7 +200,8 @@  static bool try_load_elf64(struct elf_hdr *header)
 			break;
 	}
 
-	if (i == kh->e_shnum || !(sh->sh_flags & ELF_SFLAGS_X)) {
+	if ((kh->e_flags & EF_ELF_ABI_V1) &&
+	    (i == kh->e_shnum || !(sh->sh_flags & ELF_SFLAGS_X))) {
 		kernel_entry = *(uint64_t *)(kernel_entry + load_base);
 		kernel_entry = kernel_entry - ph->p_vaddr + ph->p_offset;
 	}
diff --git a/include/elf.h b/include/elf.h
index 93524bb99a4a..f981b374ea32 100644
--- a/include/elf.h
+++ b/include/elf.h
@@ -39,6 +39,8 @@  struct elf64_hdr {
 	uint64_t e_phoff;
 	uint64_t e_shoff;
 	uint32_t e_flags;
+#define EF_ELF_ABI_V1 0x1
+#define EF_ELF_ABI_V2 0x2
 	uint16_t e_ehsize;
 	uint16_t e_phentsize;
 	uint16_t e_phnum;