From 50b2b2e691cd4ff30331ba9a6156b29a07b60f90 Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Sat, 22 Jul 2017 01:02:40 -0400 Subject: ARM: add ELF_FDPIC support This includes the necessary code to recognise the FDPIC format on ARM and the ptrace command definitions used by the common ptrace code. Based on patches originally from Mickael Guene . Signed-off-by: Nicolas Pitre Acked-by: Mickael GUENE Tested-by: Vincent Abriou Tested-by: Andras Szemzo --- fs/Kconfig.binfmt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'fs') diff --git a/fs/Kconfig.binfmt b/fs/Kconfig.binfmt index b2f82cf6bf86..6ef70ce8e976 100644 --- a/fs/Kconfig.binfmt +++ b/fs/Kconfig.binfmt @@ -35,7 +35,7 @@ config ARCH_BINFMT_ELF_STATE config BINFMT_ELF_FDPIC bool "Kernel support for FDPIC ELF binaries" default y - depends on (FRV || BLACKFIN || (SUPERH32 && !MMU) || C6X) + depends on ((ARM && !MMU) || FRV || BLACKFIN || (SUPERH32 && !MMU) || C6X) select ELFCORE help ELF FDPIC binaries are based on ELF, but allow the individual load -- cgit v1.2.3-70-g09d2 From 382e67aec6a7eea8ed4403e86950b468a191c468 Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Fri, 11 Aug 2017 00:53:39 -0400 Subject: ARM: enable elf_fdpic on systems with an MMU Provide the necessary changes to be able to execute ELF-FDPIC binaries on ARM systems with an MMU. The default for CONFIG_BINFMT_ELF_FDPIC is also set to n if the regular ELF loader is already configured so not to force FDPIC support on everyone. Given that CONFIG_BINFMT_ELF depends on CONFIG_MMU, this means CONFIG_BINFMT_ELF_FDPIC will still default to y when !MMU. Signed-off-by: Nicolas Pitre Acked-by: Mickael GUENE Tested-by: Vincent Abriou Tested-by: Andras Szemzo --- arch/arm/include/asm/mmu.h | 4 ++++ arch/arm/kernel/elf.c | 22 ++++++++++++++++++++++ fs/Kconfig.binfmt | 4 ++-- fs/binfmt_elf_fdpic.c | 5 +++++ 4 files changed, 33 insertions(+), 2 deletions(-) (limited to 'fs') diff --git a/arch/arm/include/asm/mmu.h b/arch/arm/include/asm/mmu.h index e0eb16680a5b..bdec37c6ac35 100644 --- a/arch/arm/include/asm/mmu.h +++ b/arch/arm/include/asm/mmu.h @@ -14,6 +14,10 @@ typedef struct { #ifdef CONFIG_VDSO unsigned long vdso; #endif +#ifdef CONFIG_BINFMT_ELF_FDPIC + unsigned long exec_fdpic_loadmap; + unsigned long interp_fdpic_loadmap; +#endif } mm_context_t; #ifdef CONFIG_CPU_HAS_ASID diff --git a/arch/arm/kernel/elf.c b/arch/arm/kernel/elf.c index 52fb98358d9d..569e69ece5ca 100644 --- a/arch/arm/kernel/elf.c +++ b/arch/arm/kernel/elf.c @@ -3,6 +3,7 @@ #include #include #include +#include #include int elf_check_arch(const struct elf32_hdr *x) @@ -89,3 +90,24 @@ int arm_elf_read_implies_exec(int executable_stack) return 0; } EXPORT_SYMBOL(arm_elf_read_implies_exec); + +#if defined(CONFIG_MMU) && defined(CONFIG_BINFMT_ELF_FDPIC) + +void elf_fdpic_arch_lay_out_mm(struct elf_fdpic_params *exec_params, + struct elf_fdpic_params *interp_params, + unsigned long *start_stack, + unsigned long *start_brk) +{ + elf_set_personality(&exec_params->hdr); + + exec_params->load_addr = 0x8000; + interp_params->load_addr = ELF_ET_DYN_BASE; + *start_stack = TASK_SIZE - SZ_16M; + + if ((exec_params->flags & ELF_FDPIC_FLAG_ARRANGEMENT) == ELF_FDPIC_FLAG_INDEPENDENT) { + exec_params->flags &= ~ELF_FDPIC_FLAG_ARRANGEMENT; + exec_params->flags |= ELF_FDPIC_FLAG_CONSTDISP; + } +} + +#endif diff --git a/fs/Kconfig.binfmt b/fs/Kconfig.binfmt index 6ef70ce8e976..58c2bbd385ad 100644 --- a/fs/Kconfig.binfmt +++ b/fs/Kconfig.binfmt @@ -34,8 +34,8 @@ config ARCH_BINFMT_ELF_STATE config BINFMT_ELF_FDPIC bool "Kernel support for FDPIC ELF binaries" - default y - depends on ((ARM && !MMU) || FRV || BLACKFIN || (SUPERH32 && !MMU) || C6X) + default y if !BINFMT_ELF + depends on (ARM || FRV || BLACKFIN || (SUPERH32 && !MMU) || C6X) select ELFCORE help ELF FDPIC binaries are based on ELF, but allow the individual load diff --git a/fs/binfmt_elf_fdpic.c b/fs/binfmt_elf_fdpic.c index cf93a4fad012..692e2a1fd2bb 100644 --- a/fs/binfmt_elf_fdpic.c +++ b/fs/binfmt_elf_fdpic.c @@ -377,6 +377,11 @@ static int load_elf_fdpic_binary(struct linux_binprm *bprm) executable_stack); if (retval < 0) goto error; +#ifdef ARCH_HAS_SETUP_ADDITIONAL_PAGES + retval = arch_setup_additional_pages(bprm, !!interpreter_name); + if (retval < 0) + goto error; +#endif #endif /* load the executable and interpreter into memory */ -- cgit v1.2.3-70-g09d2 From 4755200b6b116dbf6d5545427e8a2cf58194ba6b Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Wed, 16 Aug 2017 16:05:13 -0400 Subject: binfmt_elf: don't attempt to load FDPIC binaries On platforms where both ELF and ELF-FDPIC variants are available, the regular ELF loader will happily identify FDPIC binaries as proper ELF and load them without the necessary FDPIC fixups, resulting in an immediate user space crash. Let's prevent binflt_elf from loading those binaries so binfmt_elf_fdpic has a chance to pick them up. For those architectures that don't define elf_check_fdpic(), a default version returning false is provided. Signed-off-by: Nicolas Pitre Acked-by: Mickael GUENE Tested-by: Vincent Abriou Tested-by: Andras Szemzo --- fs/binfmt_elf.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) (limited to 'fs') diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index 6466153f2bf0..89536811d8f8 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c @@ -51,6 +51,11 @@ #define user_siginfo_t siginfo_t #endif +/* That's for binfmt_elf_fdpic to deal with */ +#ifndef elf_check_fdpic +#define elf_check_fdpic(ex) false +#endif + static int load_elf_binary(struct linux_binprm *bprm); static unsigned long elf_map(struct file *, unsigned long, struct elf_phdr *, int, int, unsigned long); @@ -541,7 +546,8 @@ static unsigned long load_elf_interp(struct elfhdr *interp_elf_ex, if (interp_elf_ex->e_type != ET_EXEC && interp_elf_ex->e_type != ET_DYN) goto out; - if (!elf_check_arch(interp_elf_ex)) + if (!elf_check_arch(interp_elf_ex) || + elf_check_fdpic(interp_elf_ex)) goto out; if (!interpreter->f_op->mmap) goto out; @@ -717,6 +723,8 @@ static int load_elf_binary(struct linux_binprm *bprm) goto out; if (!elf_check_arch(&loc->elf_ex)) goto out; + if (elf_check_fdpic(&loc->elf_ex)) + goto out; if (!bprm->file->f_op->mmap) goto out; @@ -816,7 +824,8 @@ static int load_elf_binary(struct linux_binprm *bprm) if (memcmp(loc->interp_elf_ex.e_ident, ELFMAG, SELFMAG) != 0) goto out_free_dentry; /* Verify the interpreter has a valid arch */ - if (!elf_check_arch(&loc->interp_elf_ex)) + if (!elf_check_arch(&loc->interp_elf_ex) || + elf_check_fdpic(&loc->interp_elf_ex)) goto out_free_dentry; /* Load the interpreter program headers */ @@ -1188,6 +1197,8 @@ static int load_elf_library(struct file *file) if (elf_ex.e_type != ET_EXEC || elf_ex.e_phnum > 2 || !elf_check_arch(&elf_ex) || !file->f_op->mmap) goto out; + if (elf_check_fdpic(&elf_ex)) + goto out; /* Now read in all of the header information */ -- cgit v1.2.3-70-g09d2 From cdf38888ed30523b1a6ee199449a86dbd1d864ce Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Wed, 16 Aug 2017 18:56:14 -0400 Subject: binfmt_elf_fdpic: fix crash on MMU system with dynamic binaries In elf_fdpic_map_file() there is a test to ensure the dynamic section in user space is properly terminated. However it does so by dereferencing a user address directly. Add proper user space accessor. Signed-off-by: Nicolas Pitre Acked-by: Mickael GUENE Tested-by: Vincent Abriou Tested-by: Andras Szemzo --- fs/binfmt_elf_fdpic.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'fs') diff --git a/fs/binfmt_elf_fdpic.c b/fs/binfmt_elf_fdpic.c index 692e2a1fd2bb..6a56dea13876 100644 --- a/fs/binfmt_elf_fdpic.c +++ b/fs/binfmt_elf_fdpic.c @@ -835,6 +835,9 @@ static int elf_fdpic_map_file(struct elf_fdpic_params *params, if (phdr->p_vaddr >= seg->p_vaddr && phdr->p_vaddr + phdr->p_memsz <= seg->p_vaddr + seg->p_memsz) { + Elf32_Dyn __user *dyn; + Elf32_Sword d_tag; + params->dynamic_addr = (phdr->p_vaddr - seg->p_vaddr) + seg->addr; @@ -847,8 +850,9 @@ static int elf_fdpic_map_file(struct elf_fdpic_params *params, goto dynamic_error; tmp = phdr->p_memsz / sizeof(Elf32_Dyn); - if (((Elf32_Dyn *) - params->dynamic_addr)[tmp - 1].d_tag != 0) + dyn = (Elf32_Dyn __user *)params->dynamic_addr; + __get_user(d_tag, &dyn[tmp - 1].d_tag); + if (d_tag != 0) goto dynamic_error; break; } -- cgit v1.2.3-70-g09d2