[Skiboot] [PATCH] core/init: Check BE elf version before assuming behaviour

Jordan Niethe jniethe5 at gmail.com
Mon Dec 16 15:58:26 AEDT 2019


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 at gmail.com>
---
 core/init.c   | 15 ++++++++++-----
 include/elf.h |  2 ++
 2 files changed, 12 insertions(+), 5 deletions(-)

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;
-- 
2.17.1



More information about the Skiboot mailing list