diff mbox

Let the ELF binfmts test against the OSABI field.

Message ID 1457014538-1185-1-git-send-email-ed@nuxi.nl (mailing list archive)
State New, archived
Headers show

Commit Message

Ed Schouten March 3, 2016, 2:15 p.m. UTC
While implementing an alternative binfmt for a pure capability-based
runtime environment[1], I noticed that our current binfmts don't test
against the OSABI field. This can for example be observed by trying to
execute a (statically linked) FreeBSD binary on Linux:

$ ./sbin/init
zsh: segmentation fault (core dumped)  ./sbin/init

Introduce a new macro called elf_check_linux_magic() that we can use to
validate that an ELF header is suitable for use on Linux, similar to how
the existing elf_check_arch() macro validates that an ELF header is
suitable for the current architecture. Let this macro match both
ELFOSABI_NONE and ELFOSABI_LINUX, as the former is actually used more
commonly.

This allows people to experiment with custom ELF binfmts without having
the standard binfmt taking preference. If we now try to execute our
FreeBSD binary we get an error message instead, as no matching binfmt
exists:

$ ./sbin/init
zsh: exec format error: ./sbin/init

[1] CloudABI: https://www.youtube.com/watch?v=62cYMmSY2Dc

Signed-off-by: Ed Schouten <ed@nuxi.nl>
---
 fs/binfmt_elf.c       | 6 +++---
 fs/binfmt_elf_fdpic.c | 2 +-
 fs/binfmt_em86.c      | 2 +-
 include/linux/elf.h   | 9 +++++++++
 4 files changed, 14 insertions(+), 5 deletions(-)
diff mbox

Patch

diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c
index 7d914c6..95b1ece 100644
--- a/fs/binfmt_elf.c
+++ b/fs/binfmt_elf.c
@@ -697,7 +697,7 @@  static int load_elf_binary(struct linux_binprm *bprm)
 
 	retval = -ENOEXEC;
 	/* First of all, some simple consistency checks */
-	if (memcmp(loc->elf_ex.e_ident, ELFMAG, SELFMAG) != 0)
+	if (!elf_check_linux_magic(&loc->elf_ex))
 		goto out;
 
 	if (loc->elf_ex.e_type != ET_EXEC && loc->elf_ex.e_type != ET_DYN)
@@ -800,7 +800,7 @@  static int load_elf_binary(struct linux_binprm *bprm)
 	if (elf_interpreter) {
 		retval = -ELIBBAD;
 		/* Not an ELF interpreter */
-		if (memcmp(loc->interp_elf_ex.e_ident, ELFMAG, SELFMAG) != 0)
+		if (!elf_check_linux_magic(&loc->interp_elf_ex))
 			goto out_free_dentry;
 		/* Verify the interpreter has a valid arch */
 		if (!elf_check_arch(&loc->interp_elf_ex))
@@ -1122,7 +1122,7 @@  static int load_elf_library(struct file *file)
 	if (retval != sizeof(elf_ex))
 		goto out;
 
-	if (memcmp(elf_ex.e_ident, ELFMAG, SELFMAG) != 0)
+	if (!elf_check_linux_magic(&elf_ex))
 		goto out;
 
 	/* First of all, some simple consistency checks */
diff --git a/fs/binfmt_elf_fdpic.c b/fs/binfmt_elf_fdpic.c
index b1adb92..4000005 100644
--- a/fs/binfmt_elf_fdpic.c
+++ b/fs/binfmt_elf_fdpic.c
@@ -106,7 +106,7 @@  module_exit(exit_elf_fdpic_binfmt);
 
 static int is_elf(struct elfhdr *hdr, struct file *file)
 {
-	if (memcmp(hdr->e_ident, ELFMAG, SELFMAG) != 0)
+	if (!elf_check_linux_magic(hdr))
 		return 0;
 	if (hdr->e_type != ET_EXEC && hdr->e_type != ET_DYN)
 		return 0;
diff --git a/fs/binfmt_em86.c b/fs/binfmt_em86.c
index 4905385..fc68231 100644
--- a/fs/binfmt_em86.c
+++ b/fs/binfmt_em86.c
@@ -32,7 +32,7 @@  static int load_em86(struct linux_binprm *bprm)
 	/* Make sure this is a Linux/Intel ELF executable... */
 	elf_ex = *((struct elfhdr *)bprm->buf);
 
-	if (memcmp(elf_ex.e_ident, ELFMAG, SELFMAG) != 0)
+	if (!elf_check_linux_magic(&elf_ex))
 		return  -ENOEXEC;
 
 	/* First of all, some simple consistency checks */
diff --git a/include/linux/elf.h b/include/linux/elf.h
index 20fa8d8..f1ed95b 100644
--- a/include/linux/elf.h
+++ b/include/linux/elf.h
@@ -46,6 +46,15 @@  extern Elf64_Dyn _DYNAMIC [];
 struct file;
 struct coredump_params;
 
+/*
+ * Returns true if the ELF header corresponds with a valid ELF file that
+ * is supposed to be used on Linux.
+ */
+#define elf_check_linux_magic(hdr) \
+	(memcmp((hdr)->e_ident, ELFMAG, SELFMAG) == 0 && \
+	 ((hdr)->e_ident[EI_OSABI] == ELFOSABI_NONE || \
+	  (hdr)->e_ident[EI_OSABI] == ELFOSABI_LINUX))
+
 #ifndef ARCH_HAVE_EXTRA_ELF_NOTES
 static inline int elf_coredump_extra_notes_size(void) { return 0; }
 static inline int elf_coredump_extra_notes_write(struct coredump_params *cprm) { return 0; }