Commit 1bb07833 authored by Russell King's avatar Russell King

Merge branch 'fdpic' of http://git.linaro.org/people/nicolas.pitre/linux into devel-stable

This series provides the needed changes to suport the ELF_FDPIC binary
format on ARM. Both MMU and non-MMU systems are supported. This format
has many advantages over the BFLT format used on MMU-less systems, such
as being real ELF that can be parsed by standard tools, can support
shared dynamic libs, etc.
parents 47624248 cdf38888
...@@ -100,10 +100,15 @@ struct elf32_hdr; ...@@ -100,10 +100,15 @@ struct elf32_hdr;
extern int elf_check_arch(const struct elf32_hdr *); extern int elf_check_arch(const struct elf32_hdr *);
#define elf_check_arch elf_check_arch #define elf_check_arch elf_check_arch
#define ELFOSABI_ARM_FDPIC 65 /* ARM FDPIC platform */
#define elf_check_fdpic(x) ((x)->e_ident[EI_OSABI] == ELFOSABI_ARM_FDPIC)
#define elf_check_const_displacement(x) ((x)->e_flags & EF_ARM_PIC)
#define ELF_FDPIC_CORE_EFLAGS 0
#define vmcore_elf64_check_arch(x) (0) #define vmcore_elf64_check_arch(x) (0)
extern int arm_elf_read_implies_exec(const struct elf32_hdr *, int); extern int arm_elf_read_implies_exec(int);
#define elf_read_implies_exec(ex,stk) arm_elf_read_implies_exec(&(ex), stk) #define elf_read_implies_exec(ex,stk) arm_elf_read_implies_exec(stk)
struct task_struct; struct task_struct;
int dump_task_regs(struct task_struct *t, elf_gregset_t *elfregs); int dump_task_regs(struct task_struct *t, elf_gregset_t *elfregs);
...@@ -120,6 +125,13 @@ int dump_task_regs(struct task_struct *t, elf_gregset_t *elfregs); ...@@ -120,6 +125,13 @@ int dump_task_regs(struct task_struct *t, elf_gregset_t *elfregs);
have no such handler. */ have no such handler. */
#define ELF_PLAT_INIT(_r, load_addr) (_r)->ARM_r0 = 0 #define ELF_PLAT_INIT(_r, load_addr) (_r)->ARM_r0 = 0
#define ELF_FDPIC_PLAT_INIT(_r, _exec_map_addr, _interp_map_addr, dynamic_addr) \
do { \
(_r)->ARM_r7 = _exec_map_addr; \
(_r)->ARM_r8 = _interp_map_addr; \
(_r)->ARM_r9 = dynamic_addr; \
} while(0)
extern void elf_set_personality(const struct elf32_hdr *); extern void elf_set_personality(const struct elf32_hdr *);
#define SET_PERSONALITY(ex) elf_set_personality(&(ex)) #define SET_PERSONALITY(ex) elf_set_personality(&(ex))
......
...@@ -14,6 +14,10 @@ typedef struct { ...@@ -14,6 +14,10 @@ typedef struct {
#ifdef CONFIG_VDSO #ifdef CONFIG_VDSO
unsigned long vdso; unsigned long vdso;
#endif #endif
#ifdef CONFIG_BINFMT_ELF_FDPIC
unsigned long exec_fdpic_loadmap;
unsigned long interp_fdpic_loadmap;
#endif
} mm_context_t; } mm_context_t;
#ifdef CONFIG_CPU_HAS_ASID #ifdef CONFIG_CPU_HAS_ASID
...@@ -33,6 +37,10 @@ typedef struct { ...@@ -33,6 +37,10 @@ typedef struct {
*/ */
typedef struct { typedef struct {
unsigned long end_brk; unsigned long end_brk;
#ifdef CONFIG_BINFMT_ELF_FDPIC
unsigned long exec_fdpic_loadmap;
unsigned long interp_fdpic_loadmap;
#endif
} mm_context_t; } mm_context_t;
#endif #endif
......
...@@ -47,15 +47,24 @@ struct thread_struct { ...@@ -47,15 +47,24 @@ struct thread_struct {
#define INIT_THREAD { } #define INIT_THREAD { }
#ifdef CONFIG_MMU
#define nommu_start_thread(regs) do { } while (0)
#else
#define nommu_start_thread(regs) regs->ARM_r10 = current->mm->start_data
#endif
#define start_thread(regs,pc,sp) \ #define start_thread(regs,pc,sp) \
({ \ ({ \
unsigned long r7, r8, r9; \
\
if (IS_ENABLED(CONFIG_BINFMT_ELF_FDPIC)) { \
r7 = regs->ARM_r7; \
r8 = regs->ARM_r8; \
r9 = regs->ARM_r9; \
} \
memset(regs->uregs, 0, sizeof(regs->uregs)); \ memset(regs->uregs, 0, sizeof(regs->uregs)); \
if (IS_ENABLED(CONFIG_BINFMT_ELF_FDPIC) && \
current->personality & FDPIC_FUNCPTRS) { \
regs->ARM_r7 = r7; \
regs->ARM_r8 = r8; \
regs->ARM_r9 = r9; \
regs->ARM_r10 = current->mm->start_data; \
} else if (!IS_ENABLED(CONFIG_MMU)) \
regs->ARM_r10 = current->mm->start_data; \
if (current->personality & ADDR_LIMIT_32BIT) \ if (current->personality & ADDR_LIMIT_32BIT) \
regs->ARM_cpsr = USR_MODE; \ regs->ARM_cpsr = USR_MODE; \
else \ else \
...@@ -65,7 +74,6 @@ struct thread_struct { ...@@ -65,7 +74,6 @@ struct thread_struct {
regs->ARM_cpsr |= PSR_ENDSTATE; \ regs->ARM_cpsr |= PSR_ENDSTATE; \
regs->ARM_pc = pc & ~1; /* pc */ \ regs->ARM_pc = pc & ~1; /* pc */ \
regs->ARM_sp = sp; /* sp */ \ regs->ARM_sp = sp; /* sp */ \
nommu_start_thread(regs); \
}) })
/* Forward declaration, a strange C thing */ /* Forward declaration, a strange C thing */
......
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
#define _ASMARM_UCONTEXT_H #define _ASMARM_UCONTEXT_H
#include <asm/fpstate.h> #include <asm/fpstate.h>
#include <asm/user.h>
/* /*
* struct sigcontext only has room for the basic registers, but struct * struct sigcontext only has room for the basic registers, but struct
......
...@@ -31,6 +31,10 @@ ...@@ -31,6 +31,10 @@
#define PTRACE_SETVFPREGS 28 #define PTRACE_SETVFPREGS 28
#define PTRACE_GETHBPREGS 29 #define PTRACE_GETHBPREGS 29
#define PTRACE_SETHBPREGS 30 #define PTRACE_SETHBPREGS 30
#define PTRACE_GETFDPIC 31
#define PTRACE_GETFDPIC_EXEC 0
#define PTRACE_GETFDPIC_INTERP 1
/* /*
* PSR bits * PSR bits
......
...@@ -35,5 +35,6 @@ ...@@ -35,5 +35,6 @@
#define __ARM_NR_usr26 (__ARM_NR_BASE+3) #define __ARM_NR_usr26 (__ARM_NR_BASE+3)
#define __ARM_NR_usr32 (__ARM_NR_BASE+4) #define __ARM_NR_usr32 (__ARM_NR_BASE+4)
#define __ARM_NR_set_tls (__ARM_NR_BASE+5) #define __ARM_NR_set_tls (__ARM_NR_BASE+5)
#define __ARM_NR_get_tls (__ARM_NR_BASE+6)
#endif /* _UAPI__ASM_ARM_UNISTD_H */ #endif /* _UAPI__ASM_ARM_UNISTD_H */
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
#include <asm/vdso_datapage.h> #include <asm/vdso_datapage.h>
#include <asm/hardware/cache-l2x0.h> #include <asm/hardware/cache-l2x0.h>
#include <linux/kbuild.h> #include <linux/kbuild.h>
#include "signal.h"
/* /*
* Make sure that the compiler and target are compatible. * Make sure that the compiler and target are compatible.
...@@ -112,6 +113,9 @@ int main(void) ...@@ -112,6 +113,9 @@ int main(void)
DEFINE(SVC_ADDR_LIMIT, offsetof(struct svc_pt_regs, addr_limit)); DEFINE(SVC_ADDR_LIMIT, offsetof(struct svc_pt_regs, addr_limit));
DEFINE(SVC_REGS_SIZE, sizeof(struct svc_pt_regs)); DEFINE(SVC_REGS_SIZE, sizeof(struct svc_pt_regs));
BLANK(); BLANK();
DEFINE(SIGFRAME_RC3_OFFSET, offsetof(struct sigframe, retcode[3]));
DEFINE(RT_SIGFRAME_RC3_OFFSET, offsetof(struct rt_sigframe, sig.retcode[3]));
BLANK();
#ifdef CONFIG_CACHE_L2X0 #ifdef CONFIG_CACHE_L2X0
DEFINE(L2X0_R_PHY_BASE, offsetof(struct l2x0_regs, phy_base)); DEFINE(L2X0_R_PHY_BASE, offsetof(struct l2x0_regs, phy_base));
DEFINE(L2X0_R_AUX_CTRL, offsetof(struct l2x0_regs, aux_ctrl)); DEFINE(L2X0_R_AUX_CTRL, offsetof(struct l2x0_regs, aux_ctrl));
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
#include <linux/personality.h> #include <linux/personality.h>
#include <linux/binfmts.h> #include <linux/binfmts.h>
#include <linux/elf.h> #include <linux/elf.h>
#include <linux/elf-fdpic.h>
#include <asm/system_info.h> #include <asm/system_info.h>
int elf_check_arch(const struct elf32_hdr *x) int elf_check_arch(const struct elf32_hdr *x)
...@@ -80,7 +81,7 @@ EXPORT_SYMBOL(elf_set_personality); ...@@ -80,7 +81,7 @@ EXPORT_SYMBOL(elf_set_personality);
* - the binary requires an executable stack * - the binary requires an executable stack
* - we're running on a CPU which doesn't support NX. * - we're running on a CPU which doesn't support NX.
*/ */
int arm_elf_read_implies_exec(const struct elf32_hdr *x, int executable_stack) int arm_elf_read_implies_exec(int executable_stack)
{ {
if (executable_stack != EXSTACK_DISABLE_X) if (executable_stack != EXSTACK_DISABLE_X)
return 1; return 1;
...@@ -89,3 +90,24 @@ int arm_elf_read_implies_exec(const struct elf32_hdr *x, int executable_stack) ...@@ -89,3 +90,24 @@ int arm_elf_read_implies_exec(const struct elf32_hdr *x, int executable_stack)
return 0; return 0;
} }
EXPORT_SYMBOL(arm_elf_read_implies_exec); 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
...@@ -19,11 +19,12 @@ ...@@ -19,11 +19,12 @@
#include <asm/elf.h> #include <asm/elf.h>
#include <asm/cacheflush.h> #include <asm/cacheflush.h>
#include <asm/traps.h> #include <asm/traps.h>
#include <asm/ucontext.h>
#include <asm/unistd.h> #include <asm/unistd.h>
#include <asm/vfp.h> #include <asm/vfp.h>
extern const unsigned long sigreturn_codes[7]; #include "signal.h"
extern const unsigned long sigreturn_codes[17];
static unsigned long signal_return_offset; static unsigned long signal_return_offset;
...@@ -172,15 +173,6 @@ static int restore_vfp_context(char __user **auxp) ...@@ -172,15 +173,6 @@ static int restore_vfp_context(char __user **auxp)
/* /*
* Do a signal return; undo the signal stack. These are aligned to 64-bit. * Do a signal return; undo the signal stack. These are aligned to 64-bit.
*/ */
struct sigframe {
struct ucontext uc;
unsigned long retcode[2];
};
struct rt_sigframe {
struct siginfo info;
struct sigframe sig;
};
static int restore_sigframe(struct pt_regs *regs, struct sigframe __user *sf) static int restore_sigframe(struct pt_regs *regs, struct sigframe __user *sf)
{ {
...@@ -366,9 +358,20 @@ setup_return(struct pt_regs *regs, struct ksignal *ksig, ...@@ -366,9 +358,20 @@ setup_return(struct pt_regs *regs, struct ksignal *ksig,
unsigned long __user *rc, void __user *frame) unsigned long __user *rc, void __user *frame)
{ {
unsigned long handler = (unsigned long)ksig->ka.sa.sa_handler; unsigned long handler = (unsigned long)ksig->ka.sa.sa_handler;
unsigned long handler_fdpic_GOT = 0;
unsigned long retcode; unsigned long retcode;
int thumb = 0; unsigned int idx, thumb = 0;
unsigned long cpsr = regs->ARM_cpsr & ~(PSR_f | PSR_E_BIT); unsigned long cpsr = regs->ARM_cpsr & ~(PSR_f | PSR_E_BIT);
bool fdpic = IS_ENABLED(CONFIG_BINFMT_ELF_FDPIC) &&
(current->personality & FDPIC_FUNCPTRS);
if (fdpic) {
unsigned long __user *fdpic_func_desc =
(unsigned long __user *)handler;
if (__get_user(handler, &fdpic_func_desc[0]) ||
__get_user(handler_fdpic_GOT, &fdpic_func_desc[1]))
return 1;
}
cpsr |= PSR_ENDSTATE; cpsr |= PSR_ENDSTATE;
...@@ -408,9 +411,26 @@ setup_return(struct pt_regs *regs, struct ksignal *ksig, ...@@ -408,9 +411,26 @@ setup_return(struct pt_regs *regs, struct ksignal *ksig,
if (ksig->ka.sa.sa_flags & SA_RESTORER) { if (ksig->ka.sa.sa_flags & SA_RESTORER) {
retcode = (unsigned long)ksig->ka.sa.sa_restorer; retcode = (unsigned long)ksig->ka.sa.sa_restorer;
if (fdpic) {
/*
* We need code to load the function descriptor.
* That code follows the standard sigreturn code
* (6 words), and is made of 3 + 2 words for each
* variant. The 4th copied word is the actual FD
* address that the assembly code expects.
*/
idx = 6 + thumb * 3;
if (ksig->ka.sa.sa_flags & SA_SIGINFO)
idx += 5;
if (__put_user(sigreturn_codes[idx], rc ) ||
__put_user(sigreturn_codes[idx+1], rc+1) ||
__put_user(sigreturn_codes[idx+2], rc+2) ||
__put_user(retcode, rc+3))
return 1;
goto rc_finish;
}
} else { } else {
unsigned int idx = thumb << 1; idx = thumb << 1;
if (ksig->ka.sa.sa_flags & SA_SIGINFO) if (ksig->ka.sa.sa_flags & SA_SIGINFO)
idx += 3; idx += 3;
...@@ -422,6 +442,7 @@ setup_return(struct pt_regs *regs, struct ksignal *ksig, ...@@ -422,6 +442,7 @@ setup_return(struct pt_regs *regs, struct ksignal *ksig,
__put_user(sigreturn_codes[idx+1], rc+1)) __put_user(sigreturn_codes[idx+1], rc+1))
return 1; return 1;
rc_finish:
#ifdef CONFIG_MMU #ifdef CONFIG_MMU
if (cpsr & MODE32_BIT) { if (cpsr & MODE32_BIT) {
struct mm_struct *mm = current->mm; struct mm_struct *mm = current->mm;
...@@ -441,7 +462,7 @@ setup_return(struct pt_regs *regs, struct ksignal *ksig, ...@@ -441,7 +462,7 @@ setup_return(struct pt_regs *regs, struct ksignal *ksig,
* the return code written onto the stack. * the return code written onto the stack.
*/ */
flush_icache_range((unsigned long)rc, flush_icache_range((unsigned long)rc,
(unsigned long)(rc + 2)); (unsigned long)(rc + 3));
retcode = ((unsigned long)rc) + thumb; retcode = ((unsigned long)rc) + thumb;
} }
...@@ -451,6 +472,8 @@ setup_return(struct pt_regs *regs, struct ksignal *ksig, ...@@ -451,6 +472,8 @@ setup_return(struct pt_regs *regs, struct ksignal *ksig,
regs->ARM_sp = (unsigned long)frame; regs->ARM_sp = (unsigned long)frame;
regs->ARM_lr = retcode; regs->ARM_lr = retcode;
regs->ARM_pc = handler; regs->ARM_pc = handler;
if (fdpic)
regs->ARM_r9 = handler_fdpic_GOT;
regs->ARM_cpsr = cpsr; regs->ARM_cpsr = cpsr;
return 0; return 0;
......
#include <asm/ucontext.h>
struct sigframe {
struct ucontext uc;
unsigned long retcode[4];
};
struct rt_sigframe {
struct siginfo info;
struct sigframe sig;
};
...@@ -14,6 +14,8 @@ ...@@ -14,6 +14,8 @@
* GNU General Public License for more details. * GNU General Public License for more details.
*/ */
#include <asm/assembler.h>
#include <asm/asm-offsets.h>
#include <asm/unistd.h> #include <asm/unistd.h>
/* /*
...@@ -51,6 +53,17 @@ ARM_OK( .arm ) ...@@ -51,6 +53,17 @@ ARM_OK( .arm )
.thumb .thumb
.endm .endm
.macro arm_fdpic_slot n
.org sigreturn_codes + 24 + 20 * (\n)
ARM_OK( .arm )
.endm
.macro thumb_fdpic_slot n
.org sigreturn_codes + 24 + 20 * (\n) + 12
.thumb
.endm
#if __LINUX_ARM_ARCH__ <= 4 #if __LINUX_ARM_ARCH__ <= 4
/* /*
* Note we manually set minimally required arch that supports * Note we manually set minimally required arch that supports
...@@ -90,13 +103,46 @@ ARM_OK( swi #(__NR_rt_sigreturn)|(__NR_OABI_SYSCALL_BASE) ) ...@@ -90,13 +103,46 @@ ARM_OK( swi #(__NR_rt_sigreturn)|(__NR_OABI_SYSCALL_BASE) )
movs r7, #(__NR_rt_sigreturn - __NR_SYSCALL_BASE) movs r7, #(__NR_rt_sigreturn - __NR_SYSCALL_BASE)
swi #0 swi #0
/* ARM sigreturn restorer FDPIC bounce code snippet */
arm_fdpic_slot 0
ARM_OK( ldr r3, [sp, #SIGFRAME_RC3_OFFSET] )
ARM_OK( ldmia r3, {r3, r9} )
#ifdef CONFIG_ARM_THUMB
ARM_OK( bx r3 )
#else
ARM_OK( ret r3 )
#endif
/* Thumb sigreturn restorer FDPIC bounce code snippet */
thumb_fdpic_slot 0
ldr r3, [sp, #SIGFRAME_RC3_OFFSET]
ldmia r3, {r2, r3}
mov r9, r3
bx r2
/* ARM sigreturn_rt restorer FDPIC bounce code snippet */
arm_fdpic_slot 1
ARM_OK( ldr r3, [sp, #RT_SIGFRAME_RC3_OFFSET] )
ARM_OK( ldmia r3, {r3, r9} )
#ifdef CONFIG_ARM_THUMB
ARM_OK( bx r3 )
#else
ARM_OK( ret r3 )
#endif
/* Thumb sigreturn_rt restorer FDPIC bounce code snippet */
thumb_fdpic_slot 1
ldr r3, [sp, #RT_SIGFRAME_RC3_OFFSET]
ldmia r3, {r2, r3}
mov r9, r3
bx r2
/* /*
* Note on addtional space: setup_return in signal.c * Note on additional space: setup_return in signal.c
* algorithm uses two words copy regardless whether * always copies the same number of words regardless whether
* it is thumb case or not, so we need additional * it is thumb case or not, so we need one additional padding
* word after real last entry. * word after the last entry.
*/ */
arm_slot 2
.space 4 .space 4
.size sigreturn_codes, . - sigreturn_codes .size sigreturn_codes, . - sigreturn_codes
...@@ -647,6 +647,9 @@ asmlinkage int arm_syscall(int no, struct pt_regs *regs) ...@@ -647,6 +647,9 @@ asmlinkage int arm_syscall(int no, struct pt_regs *regs)
set_tls(regs->ARM_r0); set_tls(regs->ARM_r0);
return 0; return 0;
case NR(get_tls):
return current_thread_info()->tp_value[0];
default: default:
/* Calls 9f00xx..9f07ff are defined to return -ENOSYS /* Calls 9f00xx..9f07ff are defined to return -ENOSYS
if not implemented, rather than raising SIGILL. This if not implemented, rather than raising SIGILL. This
......
...@@ -34,8 +34,8 @@ config ARCH_BINFMT_ELF_STATE ...@@ -34,8 +34,8 @@ config ARCH_BINFMT_ELF_STATE
config BINFMT_ELF_FDPIC config BINFMT_ELF_FDPIC
bool "Kernel support for FDPIC ELF binaries" bool "Kernel support for FDPIC ELF binaries"
default y default y if !BINFMT_ELF
depends on (FRV || BLACKFIN || (SUPERH32 && !MMU) || C6X) depends on (ARM || FRV || BLACKFIN || (SUPERH32 && !MMU) || C6X)
select ELFCORE select ELFCORE
help help
ELF FDPIC binaries are based on ELF, but allow the individual load ELF FDPIC binaries are based on ELF, but allow the individual load
......
...@@ -51,6 +51,11 @@ ...@@ -51,6 +51,11 @@
#define user_siginfo_t siginfo_t #define user_siginfo_t siginfo_t
#endif #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 int load_elf_binary(struct linux_binprm *bprm);
static unsigned long elf_map(struct file *, unsigned long, struct elf_phdr *, static unsigned long elf_map(struct file *, unsigned long, struct elf_phdr *,
int, int, unsigned long); int, int, unsigned long);
...@@ -541,7 +546,8 @@ static unsigned long load_elf_interp(struct elfhdr *interp_elf_ex, ...@@ -541,7 +546,8 @@ static unsigned long load_elf_interp(struct elfhdr *interp_elf_ex,
if (interp_elf_ex->e_type != ET_EXEC && if (interp_elf_ex->e_type != ET_EXEC &&
interp_elf_ex->e_type != ET_DYN) interp_elf_ex->e_type != ET_DYN)
goto out; goto out;
if (!elf_check_arch(interp_elf_ex)) if (!elf_check_arch(interp_elf_ex) ||
elf_check_fdpic(interp_elf_ex))
goto out; goto out;
if (!interpreter->f_op->mmap) if (!interpreter->f_op->mmap)
goto out; goto out;
...@@ -718,6 +724,8 @@ static int load_elf_binary(struct linux_binprm *bprm) ...@@ -718,6 +724,8 @@ static int load_elf_binary(struct linux_binprm *bprm)
goto out; goto out;
if (!elf_check_arch(&loc->elf_ex)) if (!elf_check_arch(&loc->elf_ex))
goto out; goto out;
if (elf_check_fdpic(&loc->elf_ex))
goto out;
if (!bprm->file->f_op->mmap) if (!bprm->file->f_op->mmap)
goto out; goto out;
...@@ -817,7 +825,8 @@ static int load_elf_binary(struct linux_binprm *bprm) ...@@ -817,7 +825,8 @@ static int load_elf_binary(struct linux_binprm *bprm)
if (memcmp(loc->interp_elf_ex.e_ident, ELFMAG, SELFMAG) != 0) if (memcmp(loc->interp_elf_ex.e_ident, ELFMAG, SELFMAG) != 0)
goto out_free_dentry; goto out_free_dentry;
/* Verify the interpreter has a valid arch */ /* 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; goto out_free_dentry;
/* Load the interpreter program headers */ /* Load the interpreter program headers */
...@@ -1190,6 +1199,8 @@ static int load_elf_library(struct file *file) ...@@ -1190,6 +1199,8 @@ static int load_elf_library(struct file *file)
if (elf_ex.e_type != ET_EXEC || elf_ex.e_phnum > 2 || if (elf_ex.e_type != ET_EXEC || elf_ex.e_phnum > 2 ||
!elf_check_arch(&elf_ex) || !file->f_op->mmap) !elf_check_arch(&elf_ex) || !file->f_op->mmap)
goto out; goto out;
if (elf_check_fdpic(&elf_ex))
goto out;
/* Now read in all of the header information */ /* Now read in all of the header information */
......
...@@ -378,6 +378,11 @@ static int load_elf_fdpic_binary(struct linux_binprm *bprm) ...@@ -378,6 +378,11 @@ static int load_elf_fdpic_binary(struct linux_binprm *bprm)
executable_stack); executable_stack);
if (retval < 0) if (retval < 0)
goto error; goto error;
#ifdef ARCH_HAS_SETUP_ADDITIONAL_PAGES
retval = arch_setup_additional_pages(bprm, !!interpreter_name);
if (retval < 0)
goto error;
#endif
#endif #endif
/* load the executable and interpreter into memory */ /* load the executable and interpreter into memory */
...@@ -831,6 +836,9 @@ static int elf_fdpic_map_file(struct elf_fdpic_params *params, ...@@ -831,6 +836,9 @@ static int elf_fdpic_map_file(struct elf_fdpic_params *params,
if (phdr->p_vaddr >= seg->p_vaddr && if (phdr->p_vaddr >= seg->p_vaddr &&
phdr->p_vaddr + phdr->p_memsz <= phdr->p_vaddr + phdr->p_memsz <=
seg->p_vaddr + seg->p_memsz) { seg->p_vaddr + seg->p_memsz) {
Elf32_Dyn __user *dyn;
Elf32_Sword d_tag;
params->dynamic_addr = params->dynamic_addr =
(phdr->p_vaddr - seg->p_vaddr) + (phdr->p_vaddr - seg->p_vaddr) +
seg->addr; seg->addr;
...@@ -843,8 +851,9 @@ static int elf_fdpic_map_file(struct elf_fdpic_params *params, ...@@ -843,8 +851,9 @@ static int elf_fdpic_map_file(struct elf_fdpic_params *params,
goto dynamic_error; goto dynamic_error;
tmp = phdr->p_memsz / sizeof(Elf32_Dyn); tmp = phdr->p_memsz / sizeof(Elf32_Dyn);
if (((Elf32_Dyn *) dyn = (Elf32_Dyn __user *)params->dynamic_addr;
params->dynamic_addr)[tmp - 1].d_tag != 0) __get_user(d_tag, &dyn[tmp - 1].d_tag);
if (d_tag != 0)
goto dynamic_error; goto dynamic_error;
break; break;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment