diff options
| -rw-r--r-- | arch/arm/include/asm/elf.h | 16 | ||||
| -rw-r--r-- | arch/arm/include/asm/mmu.h | 8 | ||||
| -rw-r--r-- | arch/arm/include/asm/processor.h | 22 | ||||
| -rw-r--r-- | arch/arm/include/asm/ucontext.h | 1 | ||||
| -rw-r--r-- | arch/arm/include/uapi/asm/ptrace.h | 4 | ||||
| -rw-r--r-- | arch/arm/include/uapi/asm/unistd.h | 1 | ||||
| -rw-r--r-- | arch/arm/kernel/asm-offsets.c | 4 | ||||
| -rw-r--r-- | arch/arm/kernel/elf.c | 24 | ||||
| -rw-r--r-- | arch/arm/kernel/signal.c | 53 | ||||
| -rw-r--r-- | arch/arm/kernel/signal.h | 11 | ||||
| -rw-r--r-- | arch/arm/kernel/sigreturn_codes.S | 56 | ||||
| -rw-r--r-- | arch/arm/kernel/traps.c | 3 | ||||
| -rw-r--r-- | fs/Kconfig.binfmt | 4 | ||||
| -rw-r--r-- | fs/binfmt_elf.c | 15 | ||||
| -rw-r--r-- | fs/binfmt_elf_fdpic.c | 13 |
15 files changed, 199 insertions, 36 deletions
diff --git a/arch/arm/include/asm/elf.h b/arch/arm/include/asm/elf.h index f13ae153fb24..ad0ca4f2ba13 100644 --- a/arch/arm/include/asm/elf.h +++ b/arch/arm/include/asm/elf.h | |||
| @@ -100,10 +100,15 @@ struct elf32_hdr; | |||
| 100 | extern int elf_check_arch(const struct elf32_hdr *); | 100 | extern int elf_check_arch(const struct elf32_hdr *); |
| 101 | #define elf_check_arch elf_check_arch | 101 | #define elf_check_arch elf_check_arch |
| 102 | 102 | ||
| 103 | #define ELFOSABI_ARM_FDPIC 65 /* ARM FDPIC platform */ | ||
| 104 | #define elf_check_fdpic(x) ((x)->e_ident[EI_OSABI] == ELFOSABI_ARM_FDPIC) | ||
| 105 | #define elf_check_const_displacement(x) ((x)->e_flags & EF_ARM_PIC) | ||
| 106 | #define ELF_FDPIC_CORE_EFLAGS 0 | ||
| 107 | |||
| 103 | #define vmcore_elf64_check_arch(x) (0) | 108 | #define vmcore_elf64_check_arch(x) (0) |
| 104 | 109 | ||
| 105 | extern int arm_elf_read_implies_exec(const struct elf32_hdr *, int); | 110 | extern int arm_elf_read_implies_exec(int); |
| 106 | #define elf_read_implies_exec(ex,stk) arm_elf_read_implies_exec(&(ex), stk) | 111 | #define elf_read_implies_exec(ex,stk) arm_elf_read_implies_exec(stk) |
| 107 | 112 | ||
| 108 | struct task_struct; | 113 | struct task_struct; |
| 109 | int dump_task_regs(struct task_struct *t, elf_gregset_t *elfregs); | 114 | 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 | have no such handler. */ | 125 | have no such handler. */ |
| 121 | #define ELF_PLAT_INIT(_r, load_addr) (_r)->ARM_r0 = 0 | 126 | #define ELF_PLAT_INIT(_r, load_addr) (_r)->ARM_r0 = 0 |
| 122 | 127 | ||
| 128 | #define ELF_FDPIC_PLAT_INIT(_r, _exec_map_addr, _interp_map_addr, dynamic_addr) \ | ||
| 129 | do { \ | ||
| 130 | (_r)->ARM_r7 = _exec_map_addr; \ | ||
| 131 | (_r)->ARM_r8 = _interp_map_addr; \ | ||
| 132 | (_r)->ARM_r9 = dynamic_addr; \ | ||
| 133 | } while(0) | ||
| 134 | |||
| 123 | extern void elf_set_personality(const struct elf32_hdr *); | 135 | extern void elf_set_personality(const struct elf32_hdr *); |
| 124 | #define SET_PERSONALITY(ex) elf_set_personality(&(ex)) | 136 | #define SET_PERSONALITY(ex) elf_set_personality(&(ex)) |
| 125 | 137 | ||
diff --git a/arch/arm/include/asm/mmu.h b/arch/arm/include/asm/mmu.h index a5b47421059d..bdec37c6ac35 100644 --- a/arch/arm/include/asm/mmu.h +++ b/arch/arm/include/asm/mmu.h | |||
| @@ -14,6 +14,10 @@ typedef struct { | |||
| 14 | #ifdef CONFIG_VDSO | 14 | #ifdef CONFIG_VDSO |
| 15 | unsigned long vdso; | 15 | unsigned long vdso; |
| 16 | #endif | 16 | #endif |
| 17 | #ifdef CONFIG_BINFMT_ELF_FDPIC | ||
| 18 | unsigned long exec_fdpic_loadmap; | ||
| 19 | unsigned long interp_fdpic_loadmap; | ||
| 20 | #endif | ||
| 17 | } mm_context_t; | 21 | } mm_context_t; |
| 18 | 22 | ||
| 19 | #ifdef CONFIG_CPU_HAS_ASID | 23 | #ifdef CONFIG_CPU_HAS_ASID |
| @@ -33,6 +37,10 @@ typedef struct { | |||
| 33 | */ | 37 | */ |
| 34 | typedef struct { | 38 | typedef struct { |
| 35 | unsigned long end_brk; | 39 | unsigned long end_brk; |
| 40 | #ifdef CONFIG_BINFMT_ELF_FDPIC | ||
| 41 | unsigned long exec_fdpic_loadmap; | ||
| 42 | unsigned long interp_fdpic_loadmap; | ||
| 43 | #endif | ||
| 36 | } mm_context_t; | 44 | } mm_context_t; |
| 37 | 45 | ||
| 38 | #endif | 46 | #endif |
diff --git a/arch/arm/include/asm/processor.h b/arch/arm/include/asm/processor.h index c3d5fc124a05..338cbe0a18ef 100644 --- a/arch/arm/include/asm/processor.h +++ b/arch/arm/include/asm/processor.h | |||
| @@ -47,15 +47,24 @@ struct thread_struct { | |||
| 47 | 47 | ||
| 48 | #define INIT_THREAD { } | 48 | #define INIT_THREAD { } |
| 49 | 49 | ||
| 50 | #ifdef CONFIG_MMU | ||
| 51 | #define nommu_start_thread(regs) do { } while (0) | ||
| 52 | #else | ||
| 53 | #define nommu_start_thread(regs) regs->ARM_r10 = current->mm->start_data | ||
| 54 | #endif | ||
| 55 | |||
| 56 | #define start_thread(regs,pc,sp) \ | 50 | #define start_thread(regs,pc,sp) \ |
| 57 | ({ \ | 51 | ({ \ |
| 52 | unsigned long r7, r8, r9; \ | ||
| 53 | \ | ||
| 54 | if (IS_ENABLED(CONFIG_BINFMT_ELF_FDPIC)) { \ | ||
| 55 | r7 = regs->ARM_r7; \ | ||
| 56 | r8 = regs->ARM_r8; \ | ||
| 57 | r9 = regs->ARM_r9; \ | ||
| 58 | } \ | ||
| 58 | memset(regs->uregs, 0, sizeof(regs->uregs)); \ | 59 | memset(regs->uregs, 0, sizeof(regs->uregs)); \ |
| 60 | if (IS_ENABLED(CONFIG_BINFMT_ELF_FDPIC) && \ | ||
| 61 | current->personality & FDPIC_FUNCPTRS) { \ | ||
| 62 | regs->ARM_r7 = r7; \ | ||
| 63 | regs->ARM_r8 = r8; \ | ||
| 64 | regs->ARM_r9 = r9; \ | ||
| 65 | regs->ARM_r10 = current->mm->start_data; \ | ||
| 66 | } else if (!IS_ENABLED(CONFIG_MMU)) \ | ||
| 67 | regs->ARM_r10 = current->mm->start_data; \ | ||
| 59 | if (current->personality & ADDR_LIMIT_32BIT) \ | 68 | if (current->personality & ADDR_LIMIT_32BIT) \ |
| 60 | regs->ARM_cpsr = USR_MODE; \ | 69 | regs->ARM_cpsr = USR_MODE; \ |
| 61 | else \ | 70 | else \ |
| @@ -65,7 +74,6 @@ struct thread_struct { | |||
| 65 | regs->ARM_cpsr |= PSR_ENDSTATE; \ | 74 | regs->ARM_cpsr |= PSR_ENDSTATE; \ |
| 66 | regs->ARM_pc = pc & ~1; /* pc */ \ | 75 | regs->ARM_pc = pc & ~1; /* pc */ \ |
| 67 | regs->ARM_sp = sp; /* sp */ \ | 76 | regs->ARM_sp = sp; /* sp */ \ |
| 68 | nommu_start_thread(regs); \ | ||
| 69 | }) | 77 | }) |
| 70 | 78 | ||
| 71 | /* Forward declaration, a strange C thing */ | 79 | /* Forward declaration, a strange C thing */ |
diff --git a/arch/arm/include/asm/ucontext.h b/arch/arm/include/asm/ucontext.h index 921d8274855c..b42c75ae0d19 100644 --- a/arch/arm/include/asm/ucontext.h +++ b/arch/arm/include/asm/ucontext.h | |||
| @@ -2,6 +2,7 @@ | |||
| 2 | #define _ASMARM_UCONTEXT_H | 2 | #define _ASMARM_UCONTEXT_H |
| 3 | 3 | ||
| 4 | #include <asm/fpstate.h> | 4 | #include <asm/fpstate.h> |
| 5 | #include <asm/user.h> | ||
| 5 | 6 | ||
| 6 | /* | 7 | /* |
| 7 | * struct sigcontext only has room for the basic registers, but struct | 8 | * struct sigcontext only has room for the basic registers, but struct |
diff --git a/arch/arm/include/uapi/asm/ptrace.h b/arch/arm/include/uapi/asm/ptrace.h index 5af0ed1b825a..3173eb9751fd 100644 --- a/arch/arm/include/uapi/asm/ptrace.h +++ b/arch/arm/include/uapi/asm/ptrace.h | |||
| @@ -31,6 +31,10 @@ | |||
| 31 | #define PTRACE_SETVFPREGS 28 | 31 | #define PTRACE_SETVFPREGS 28 |
| 32 | #define PTRACE_GETHBPREGS 29 | 32 | #define PTRACE_GETHBPREGS 29 |
| 33 | #define PTRACE_SETHBPREGS 30 | 33 | #define PTRACE_SETHBPREGS 30 |
| 34 | #define PTRACE_GETFDPIC 31 | ||
| 35 | |||
| 36 | #define PTRACE_GETFDPIC_EXEC 0 | ||
| 37 | #define PTRACE_GETFDPIC_INTERP 1 | ||
| 34 | 38 | ||
| 35 | /* | 39 | /* |
| 36 | * PSR bits | 40 | * PSR bits |
diff --git a/arch/arm/include/uapi/asm/unistd.h b/arch/arm/include/uapi/asm/unistd.h index 28bd456494a3..575b25fc29c6 100644 --- a/arch/arm/include/uapi/asm/unistd.h +++ b/arch/arm/include/uapi/asm/unistd.h | |||
| @@ -35,5 +35,6 @@ | |||
| 35 | #define __ARM_NR_usr26 (__ARM_NR_BASE+3) | 35 | #define __ARM_NR_usr26 (__ARM_NR_BASE+3) |
| 36 | #define __ARM_NR_usr32 (__ARM_NR_BASE+4) | 36 | #define __ARM_NR_usr32 (__ARM_NR_BASE+4) |
| 37 | #define __ARM_NR_set_tls (__ARM_NR_BASE+5) | 37 | #define __ARM_NR_set_tls (__ARM_NR_BASE+5) |
| 38 | #define __ARM_NR_get_tls (__ARM_NR_BASE+6) | ||
| 38 | 39 | ||
| 39 | #endif /* _UAPI__ASM_ARM_UNISTD_H */ | 40 | #endif /* _UAPI__ASM_ARM_UNISTD_H */ |
diff --git a/arch/arm/kernel/asm-offsets.c b/arch/arm/kernel/asm-offsets.c index 608008229c7d..13c155850822 100644 --- a/arch/arm/kernel/asm-offsets.c +++ b/arch/arm/kernel/asm-offsets.c | |||
| @@ -28,6 +28,7 @@ | |||
| 28 | #include <asm/vdso_datapage.h> | 28 | #include <asm/vdso_datapage.h> |
| 29 | #include <asm/hardware/cache-l2x0.h> | 29 | #include <asm/hardware/cache-l2x0.h> |
| 30 | #include <linux/kbuild.h> | 30 | #include <linux/kbuild.h> |
| 31 | #include "signal.h" | ||
| 31 | 32 | ||
| 32 | /* | 33 | /* |
| 33 | * Make sure that the compiler and target are compatible. | 34 | * Make sure that the compiler and target are compatible. |
| @@ -112,6 +113,9 @@ int main(void) | |||
| 112 | DEFINE(SVC_ADDR_LIMIT, offsetof(struct svc_pt_regs, addr_limit)); | 113 | DEFINE(SVC_ADDR_LIMIT, offsetof(struct svc_pt_regs, addr_limit)); |
| 113 | DEFINE(SVC_REGS_SIZE, sizeof(struct svc_pt_regs)); | 114 | DEFINE(SVC_REGS_SIZE, sizeof(struct svc_pt_regs)); |
| 114 | BLANK(); | 115 | BLANK(); |
| 116 | DEFINE(SIGFRAME_RC3_OFFSET, offsetof(struct sigframe, retcode[3])); | ||
| 117 | DEFINE(RT_SIGFRAME_RC3_OFFSET, offsetof(struct rt_sigframe, sig.retcode[3])); | ||
| 118 | BLANK(); | ||
| 115 | #ifdef CONFIG_CACHE_L2X0 | 119 | #ifdef CONFIG_CACHE_L2X0 |
| 116 | DEFINE(L2X0_R_PHY_BASE, offsetof(struct l2x0_regs, phy_base)); | 120 | DEFINE(L2X0_R_PHY_BASE, offsetof(struct l2x0_regs, phy_base)); |
| 117 | DEFINE(L2X0_R_AUX_CTRL, offsetof(struct l2x0_regs, aux_ctrl)); | 121 | DEFINE(L2X0_R_AUX_CTRL, offsetof(struct l2x0_regs, aux_ctrl)); |
diff --git a/arch/arm/kernel/elf.c b/arch/arm/kernel/elf.c index d0d1e83150c9..569e69ece5ca 100644 --- a/arch/arm/kernel/elf.c +++ b/arch/arm/kernel/elf.c | |||
| @@ -3,6 +3,7 @@ | |||
| 3 | #include <linux/personality.h> | 3 | #include <linux/personality.h> |
| 4 | #include <linux/binfmts.h> | 4 | #include <linux/binfmts.h> |
| 5 | #include <linux/elf.h> | 5 | #include <linux/elf.h> |
| 6 | #include <linux/elf-fdpic.h> | ||
| 6 | #include <asm/system_info.h> | 7 | #include <asm/system_info.h> |
| 7 | 8 | ||
| 8 | int elf_check_arch(const struct elf32_hdr *x) | 9 | int elf_check_arch(const struct elf32_hdr *x) |
| @@ -80,7 +81,7 @@ EXPORT_SYMBOL(elf_set_personality); | |||
| 80 | * - the binary requires an executable stack | 81 | * - the binary requires an executable stack |
| 81 | * - we're running on a CPU which doesn't support NX. | 82 | * - we're running on a CPU which doesn't support NX. |
| 82 | */ | 83 | */ |
| 83 | int arm_elf_read_implies_exec(const struct elf32_hdr *x, int executable_stack) | 84 | int arm_elf_read_implies_exec(int executable_stack) |
| 84 | { | 85 | { |
| 85 | if (executable_stack != EXSTACK_DISABLE_X) | 86 | if (executable_stack != EXSTACK_DISABLE_X) |
| 86 | return 1; | 87 | return 1; |
| @@ -89,3 +90,24 @@ int arm_elf_read_implies_exec(const struct elf32_hdr *x, int executable_stack) | |||
| 89 | return 0; | 90 | return 0; |
| 90 | } | 91 | } |
| 91 | EXPORT_SYMBOL(arm_elf_read_implies_exec); | 92 | EXPORT_SYMBOL(arm_elf_read_implies_exec); |
| 93 | |||
| 94 | #if defined(CONFIG_MMU) && defined(CONFIG_BINFMT_ELF_FDPIC) | ||
| 95 | |||
| 96 | void elf_fdpic_arch_lay_out_mm(struct elf_fdpic_params *exec_params, | ||
| 97 | struct elf_fdpic_params *interp_params, | ||
| 98 | unsigned long *start_stack, | ||
| 99 | unsigned long *start_brk) | ||
| 100 | { | ||
| 101 | elf_set_personality(&exec_params->hdr); | ||
| 102 | |||
| 103 | exec_params->load_addr = 0x8000; | ||
| 104 | interp_params->load_addr = ELF_ET_DYN_BASE; | ||
| 105 | *start_stack = TASK_SIZE - SZ_16M; | ||
| 106 | |||
| 107 | if ((exec_params->flags & ELF_FDPIC_FLAG_ARRANGEMENT) == ELF_FDPIC_FLAG_INDEPENDENT) { | ||
| 108 | exec_params->flags &= ~ELF_FDPIC_FLAG_ARRANGEMENT; | ||
| 109 | exec_params->flags |= ELF_FDPIC_FLAG_CONSTDISP; | ||
| 110 | } | ||
| 111 | } | ||
| 112 | |||
| 113 | #endif | ||
diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c index e2de50bf8742..237973492479 100644 --- a/arch/arm/kernel/signal.c +++ b/arch/arm/kernel/signal.c | |||
| @@ -19,11 +19,12 @@ | |||
| 19 | #include <asm/elf.h> | 19 | #include <asm/elf.h> |
| 20 | #include <asm/cacheflush.h> | 20 | #include <asm/cacheflush.h> |
| 21 | #include <asm/traps.h> | 21 | #include <asm/traps.h> |
| 22 | #include <asm/ucontext.h> | ||
| 23 | #include <asm/unistd.h> | 22 | #include <asm/unistd.h> |
| 24 | #include <asm/vfp.h> | 23 | #include <asm/vfp.h> |
| 25 | 24 | ||
| 26 | extern const unsigned long sigreturn_codes[7]; | 25 | #include "signal.h" |
| 26 | |||
| 27 | extern const unsigned long sigreturn_codes[17]; | ||
| 27 | 28 | ||
| 28 | static unsigned long signal_return_offset; | 29 | static unsigned long signal_return_offset; |
| 29 | 30 | ||
| @@ -172,15 +173,6 @@ static int restore_vfp_context(char __user **auxp) | |||
| 172 | /* | 173 | /* |
| 173 | * Do a signal return; undo the signal stack. These are aligned to 64-bit. | 174 | * Do a signal return; undo the signal stack. These are aligned to 64-bit. |
| 174 | */ | 175 | */ |
| 175 | struct sigframe { | ||
| 176 | struct ucontext uc; | ||
| 177 | unsigned long retcode[2]; | ||
| 178 | }; | ||
| 179 | |||
| 180 | struct rt_sigframe { | ||
| 181 | struct siginfo info; | ||
| 182 | struct sigframe sig; | ||
| 183 | }; | ||
| 184 | 176 | ||
| 185 | static int restore_sigframe(struct pt_regs *regs, struct sigframe __user *sf) | 177 | static int restore_sigframe(struct pt_regs *regs, struct sigframe __user *sf) |
| 186 | { | 178 | { |
| @@ -366,9 +358,20 @@ setup_return(struct pt_regs *regs, struct ksignal *ksig, | |||
| 366 | unsigned long __user *rc, void __user *frame) | 358 | unsigned long __user *rc, void __user *frame) |
| 367 | { | 359 | { |
| 368 | unsigned long handler = (unsigned long)ksig->ka.sa.sa_handler; | 360 | unsigned long handler = (unsigned long)ksig->ka.sa.sa_handler; |
| 361 | unsigned long handler_fdpic_GOT = 0; | ||
| 369 | unsigned long retcode; | 362 | unsigned long retcode; |
| 370 | int thumb = 0; | 363 | unsigned int idx, thumb = 0; |
| 371 | unsigned long cpsr = regs->ARM_cpsr & ~(PSR_f | PSR_E_BIT); | 364 | unsigned long cpsr = regs->ARM_cpsr & ~(PSR_f | PSR_E_BIT); |
| 365 | bool fdpic = IS_ENABLED(CONFIG_BINFMT_ELF_FDPIC) && | ||
| 366 | (current->personality & FDPIC_FUNCPTRS); | ||
| 367 | |||
| 368 | if (fdpic) { | ||
| 369 | unsigned long __user *fdpic_func_desc = | ||
| 370 | (unsigned long __user *)handler; | ||
| 371 | if (__get_user(handler, &fdpic_func_desc[0]) || | ||
| 372 | __get_user(handler_fdpic_GOT, &fdpic_func_desc[1])) | ||
| 373 | return 1; | ||
| 374 | } | ||
| 372 | 375 | ||
| 373 | cpsr |= PSR_ENDSTATE; | 376 | cpsr |= PSR_ENDSTATE; |
| 374 | 377 | ||
| @@ -408,9 +411,26 @@ setup_return(struct pt_regs *regs, struct ksignal *ksig, | |||
| 408 | 411 | ||
| 409 | if (ksig->ka.sa.sa_flags & SA_RESTORER) { | 412 | if (ksig->ka.sa.sa_flags & SA_RESTORER) { |
| 410 | retcode = (unsigned long)ksig->ka.sa.sa_restorer; | 413 | retcode = (unsigned long)ksig->ka.sa.sa_restorer; |
| 414 | if (fdpic) { | ||
| 415 | /* | ||
| 416 | * We need code to load the function descriptor. | ||
| 417 | * That code follows the standard sigreturn code | ||
| 418 | * (6 words), and is made of 3 + 2 words for each | ||
| 419 | * variant. The 4th copied word is the actual FD | ||
| 420 | * address that the assembly code expects. | ||
| 421 | */ | ||
| 422 | idx = 6 + thumb * 3; | ||
| 423 | if (ksig->ka.sa.sa_flags & SA_SIGINFO) | ||
| 424 | idx += 5; | ||
| 425 | if (__put_user(sigreturn_codes[idx], rc ) || | ||
| 426 | __put_user(sigreturn_codes[idx+1], rc+1) || | ||
| 427 | __put_user(sigreturn_codes[idx+2], rc+2) || | ||
| 428 | __put_user(retcode, rc+3)) | ||
| 429 | return 1; | ||
| 430 | goto rc_finish; | ||
| 431 | } | ||
| 411 | } else { | 432 | } else { |
| 412 | unsigned int idx = thumb << 1; | 433 | idx = thumb << 1; |
| 413 | |||
| 414 | if (ksig->ka.sa.sa_flags & SA_SIGINFO) | 434 | if (ksig->ka.sa.sa_flags & SA_SIGINFO) |
| 415 | idx += 3; | 435 | idx += 3; |
| 416 | 436 | ||
| @@ -422,6 +442,7 @@ setup_return(struct pt_regs *regs, struct ksignal *ksig, | |||
| 422 | __put_user(sigreturn_codes[idx+1], rc+1)) | 442 | __put_user(sigreturn_codes[idx+1], rc+1)) |
| 423 | return 1; | 443 | return 1; |
| 424 | 444 | ||
| 445 | rc_finish: | ||
| 425 | #ifdef CONFIG_MMU | 446 | #ifdef CONFIG_MMU |
| 426 | if (cpsr & MODE32_BIT) { | 447 | if (cpsr & MODE32_BIT) { |
| 427 | struct mm_struct *mm = current->mm; | 448 | struct mm_struct *mm = current->mm; |
| @@ -441,7 +462,7 @@ setup_return(struct pt_regs *regs, struct ksignal *ksig, | |||
| 441 | * the return code written onto the stack. | 462 | * the return code written onto the stack. |
| 442 | */ | 463 | */ |
| 443 | flush_icache_range((unsigned long)rc, | 464 | flush_icache_range((unsigned long)rc, |
| 444 | (unsigned long)(rc + 2)); | 465 | (unsigned long)(rc + 3)); |
| 445 | 466 | ||
| 446 | retcode = ((unsigned long)rc) + thumb; | 467 | retcode = ((unsigned long)rc) + thumb; |
| 447 | } | 468 | } |
| @@ -451,6 +472,8 @@ setup_return(struct pt_regs *regs, struct ksignal *ksig, | |||
| 451 | regs->ARM_sp = (unsigned long)frame; | 472 | regs->ARM_sp = (unsigned long)frame; |
| 452 | regs->ARM_lr = retcode; | 473 | regs->ARM_lr = retcode; |
| 453 | regs->ARM_pc = handler; | 474 | regs->ARM_pc = handler; |
| 475 | if (fdpic) | ||
| 476 | regs->ARM_r9 = handler_fdpic_GOT; | ||
| 454 | regs->ARM_cpsr = cpsr; | 477 | regs->ARM_cpsr = cpsr; |
| 455 | 478 | ||
| 456 | return 0; | 479 | return 0; |
diff --git a/arch/arm/kernel/signal.h b/arch/arm/kernel/signal.h new file mode 100644 index 000000000000..b7b838b05229 --- /dev/null +++ b/arch/arm/kernel/signal.h | |||
| @@ -0,0 +1,11 @@ | |||
| 1 | #include <asm/ucontext.h> | ||
| 2 | |||
| 3 | struct sigframe { | ||
| 4 | struct ucontext uc; | ||
| 5 | unsigned long retcode[4]; | ||
| 6 | }; | ||
| 7 | |||
| 8 | struct rt_sigframe { | ||
| 9 | struct siginfo info; | ||
| 10 | struct sigframe sig; | ||
| 11 | }; | ||
diff --git a/arch/arm/kernel/sigreturn_codes.S b/arch/arm/kernel/sigreturn_codes.S index b84d0cb13682..2c7b22e32152 100644 --- a/arch/arm/kernel/sigreturn_codes.S +++ b/arch/arm/kernel/sigreturn_codes.S | |||
| @@ -14,6 +14,8 @@ | |||
| 14 | * GNU General Public License for more details. | 14 | * GNU General Public License for more details. |
| 15 | */ | 15 | */ |
| 16 | 16 | ||
| 17 | #include <asm/assembler.h> | ||
| 18 | #include <asm/asm-offsets.h> | ||
| 17 | #include <asm/unistd.h> | 19 | #include <asm/unistd.h> |
| 18 | 20 | ||
| 19 | /* | 21 | /* |
| @@ -51,6 +53,17 @@ ARM_OK( .arm ) | |||
| 51 | .thumb | 53 | .thumb |
| 52 | .endm | 54 | .endm |
| 53 | 55 | ||
| 56 | .macro arm_fdpic_slot n | ||
| 57 | .org sigreturn_codes + 24 + 20 * (\n) | ||
| 58 | ARM_OK( .arm ) | ||
| 59 | .endm | ||
| 60 | |||
| 61 | .macro thumb_fdpic_slot n | ||
| 62 | .org sigreturn_codes + 24 + 20 * (\n) + 12 | ||
| 63 | .thumb | ||
| 64 | .endm | ||
| 65 | |||
| 66 | |||
| 54 | #if __LINUX_ARM_ARCH__ <= 4 | 67 | #if __LINUX_ARM_ARCH__ <= 4 |
| 55 | /* | 68 | /* |
| 56 | * Note we manually set minimally required arch that supports | 69 | * Note we manually set minimally required arch that supports |
| @@ -90,13 +103,46 @@ ARM_OK( swi #(__NR_rt_sigreturn)|(__NR_OABI_SYSCALL_BASE) ) | |||
| 90 | movs r7, #(__NR_rt_sigreturn - __NR_SYSCALL_BASE) | 103 | movs r7, #(__NR_rt_sigreturn - __NR_SYSCALL_BASE) |
| 91 | swi #0 | 104 | swi #0 |
| 92 | 105 | ||
| 106 | /* ARM sigreturn restorer FDPIC bounce code snippet */ | ||
| 107 | arm_fdpic_slot 0 | ||
| 108 | ARM_OK( ldr r3, [sp, #SIGFRAME_RC3_OFFSET] ) | ||
| 109 | ARM_OK( ldmia r3, {r3, r9} ) | ||
| 110 | #ifdef CONFIG_ARM_THUMB | ||
| 111 | ARM_OK( bx r3 ) | ||
| 112 | #else | ||
| 113 | ARM_OK( ret r3 ) | ||
| 114 | #endif | ||
| 115 | |||
| 116 | /* Thumb sigreturn restorer FDPIC bounce code snippet */ | ||
| 117 | thumb_fdpic_slot 0 | ||
| 118 | ldr r3, [sp, #SIGFRAME_RC3_OFFSET] | ||
| 119 | ldmia r3, {r2, r3} | ||
| 120 | mov r9, r3 | ||
| 121 | bx r2 | ||
| 122 | |||
| 123 | /* ARM sigreturn_rt restorer FDPIC bounce code snippet */ | ||
| 124 | arm_fdpic_slot 1 | ||
| 125 | ARM_OK( ldr r3, [sp, #RT_SIGFRAME_RC3_OFFSET] ) | ||
| 126 | ARM_OK( ldmia r3, {r3, r9} ) | ||
| 127 | #ifdef CONFIG_ARM_THUMB | ||
| 128 | ARM_OK( bx r3 ) | ||
| 129 | #else | ||
| 130 | ARM_OK( ret r3 ) | ||
| 131 | #endif | ||
| 132 | |||
| 133 | /* Thumb sigreturn_rt restorer FDPIC bounce code snippet */ | ||
| 134 | thumb_fdpic_slot 1 | ||
| 135 | ldr r3, [sp, #RT_SIGFRAME_RC3_OFFSET] | ||
| 136 | ldmia r3, {r2, r3} | ||
| 137 | mov r9, r3 | ||
| 138 | bx r2 | ||
| 139 | |||
| 93 | /* | 140 | /* |
| 94 | * Note on addtional space: setup_return in signal.c | 141 | * Note on additional space: setup_return in signal.c |
| 95 | * algorithm uses two words copy regardless whether | 142 | * always copies the same number of words regardless whether |
| 96 | * it is thumb case or not, so we need additional | 143 | * it is thumb case or not, so we need one additional padding |
| 97 | * word after real last entry. | 144 | * word after the last entry. |
| 98 | */ | 145 | */ |
| 99 | arm_slot 2 | ||
| 100 | .space 4 | 146 | .space 4 |
| 101 | 147 | ||
| 102 | .size sigreturn_codes, . - sigreturn_codes | 148 | .size sigreturn_codes, . - sigreturn_codes |
diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c index 948c648fea00..43c0560f7b2d 100644 --- a/arch/arm/kernel/traps.c +++ b/arch/arm/kernel/traps.c | |||
| @@ -647,6 +647,9 @@ asmlinkage int arm_syscall(int no, struct pt_regs *regs) | |||
| 647 | set_tls(regs->ARM_r0); | 647 | set_tls(regs->ARM_r0); |
| 648 | return 0; | 648 | return 0; |
| 649 | 649 | ||
| 650 | case NR(get_tls): | ||
| 651 | return current_thread_info()->tp_value[0]; | ||
| 652 | |||
| 650 | default: | 653 | default: |
| 651 | /* Calls 9f00xx..9f07ff are defined to return -ENOSYS | 654 | /* Calls 9f00xx..9f07ff are defined to return -ENOSYS |
| 652 | if not implemented, rather than raising SIGILL. This | 655 | if not implemented, rather than raising SIGILL. This |
diff --git a/fs/Kconfig.binfmt b/fs/Kconfig.binfmt index b2f82cf6bf86..58c2bbd385ad 100644 --- a/fs/Kconfig.binfmt +++ b/fs/Kconfig.binfmt | |||
| @@ -34,8 +34,8 @@ config ARCH_BINFMT_ELF_STATE | |||
| 34 | 34 | ||
| 35 | config BINFMT_ELF_FDPIC | 35 | config BINFMT_ELF_FDPIC |
| 36 | bool "Kernel support for FDPIC ELF binaries" | 36 | bool "Kernel support for FDPIC ELF binaries" |
| 37 | default y | 37 | default y if !BINFMT_ELF |
| 38 | depends on (FRV || BLACKFIN || (SUPERH32 && !MMU) || C6X) | 38 | depends on (ARM || FRV || BLACKFIN || (SUPERH32 && !MMU) || C6X) |
| 39 | select ELFCORE | 39 | select ELFCORE |
| 40 | help | 40 | help |
| 41 | ELF FDPIC binaries are based on ELF, but allow the individual load | 41 | ELF FDPIC binaries are based on ELF, but allow the individual load |
diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index 73b01e474fdc..e4f7ef8294ac 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c | |||
| @@ -51,6 +51,11 @@ | |||
| 51 | #define user_siginfo_t siginfo_t | 51 | #define user_siginfo_t siginfo_t |
| 52 | #endif | 52 | #endif |
| 53 | 53 | ||
| 54 | /* That's for binfmt_elf_fdpic to deal with */ | ||
| 55 | #ifndef elf_check_fdpic | ||
| 56 | #define elf_check_fdpic(ex) false | ||
| 57 | #endif | ||
| 58 | |||
| 54 | static int load_elf_binary(struct linux_binprm *bprm); | 59 | static int load_elf_binary(struct linux_binprm *bprm); |
| 55 | static unsigned long elf_map(struct file *, unsigned long, struct elf_phdr *, | 60 | static unsigned long elf_map(struct file *, unsigned long, struct elf_phdr *, |
| 56 | int, int, unsigned long); | 61 | int, int, unsigned long); |
| @@ -541,7 +546,8 @@ static unsigned long load_elf_interp(struct elfhdr *interp_elf_ex, | |||
| 541 | if (interp_elf_ex->e_type != ET_EXEC && | 546 | if (interp_elf_ex->e_type != ET_EXEC && |
| 542 | interp_elf_ex->e_type != ET_DYN) | 547 | interp_elf_ex->e_type != ET_DYN) |
| 543 | goto out; | 548 | goto out; |
| 544 | if (!elf_check_arch(interp_elf_ex)) | 549 | if (!elf_check_arch(interp_elf_ex) || |
| 550 | elf_check_fdpic(interp_elf_ex)) | ||
| 545 | goto out; | 551 | goto out; |
| 546 | if (!interpreter->f_op->mmap) | 552 | if (!interpreter->f_op->mmap) |
| 547 | goto out; | 553 | goto out; |
| @@ -718,6 +724,8 @@ static int load_elf_binary(struct linux_binprm *bprm) | |||
| 718 | goto out; | 724 | goto out; |
| 719 | if (!elf_check_arch(&loc->elf_ex)) | 725 | if (!elf_check_arch(&loc->elf_ex)) |
| 720 | goto out; | 726 | goto out; |
| 727 | if (elf_check_fdpic(&loc->elf_ex)) | ||
| 728 | goto out; | ||
| 721 | if (!bprm->file->f_op->mmap) | 729 | if (!bprm->file->f_op->mmap) |
| 722 | goto out; | 730 | goto out; |
| 723 | 731 | ||
| @@ -817,7 +825,8 @@ static int load_elf_binary(struct linux_binprm *bprm) | |||
| 817 | if (memcmp(loc->interp_elf_ex.e_ident, ELFMAG, SELFMAG) != 0) | 825 | if (memcmp(loc->interp_elf_ex.e_ident, ELFMAG, SELFMAG) != 0) |
| 818 | goto out_free_dentry; | 826 | goto out_free_dentry; |
| 819 | /* Verify the interpreter has a valid arch */ | 827 | /* Verify the interpreter has a valid arch */ |
| 820 | if (!elf_check_arch(&loc->interp_elf_ex)) | 828 | if (!elf_check_arch(&loc->interp_elf_ex) || |
| 829 | elf_check_fdpic(&loc->interp_elf_ex)) | ||
| 821 | goto out_free_dentry; | 830 | goto out_free_dentry; |
| 822 | 831 | ||
| 823 | /* Load the interpreter program headers */ | 832 | /* Load the interpreter program headers */ |
| @@ -1190,6 +1199,8 @@ static int load_elf_library(struct file *file) | |||
| 1190 | if (elf_ex.e_type != ET_EXEC || elf_ex.e_phnum > 2 || | 1199 | if (elf_ex.e_type != ET_EXEC || elf_ex.e_phnum > 2 || |
| 1191 | !elf_check_arch(&elf_ex) || !file->f_op->mmap) | 1200 | !elf_check_arch(&elf_ex) || !file->f_op->mmap) |
| 1192 | goto out; | 1201 | goto out; |
| 1202 | if (elf_check_fdpic(&elf_ex)) | ||
| 1203 | goto out; | ||
| 1193 | 1204 | ||
| 1194 | /* Now read in all of the header information */ | 1205 | /* Now read in all of the header information */ |
| 1195 | 1206 | ||
diff --git a/fs/binfmt_elf_fdpic.c b/fs/binfmt_elf_fdpic.c index e70c039ac190..5429b035e249 100644 --- a/fs/binfmt_elf_fdpic.c +++ b/fs/binfmt_elf_fdpic.c | |||
| @@ -378,6 +378,11 @@ static int load_elf_fdpic_binary(struct linux_binprm *bprm) | |||
| 378 | executable_stack); | 378 | executable_stack); |
| 379 | if (retval < 0) | 379 | if (retval < 0) |
| 380 | goto error; | 380 | goto error; |
| 381 | #ifdef ARCH_HAS_SETUP_ADDITIONAL_PAGES | ||
| 382 | retval = arch_setup_additional_pages(bprm, !!interpreter_name); | ||
| 383 | if (retval < 0) | ||
| 384 | goto error; | ||
| 385 | #endif | ||
| 381 | #endif | 386 | #endif |
| 382 | 387 | ||
| 383 | /* load the executable and interpreter into memory */ | 388 | /* load the executable and interpreter into memory */ |
| @@ -831,6 +836,9 @@ static int elf_fdpic_map_file(struct elf_fdpic_params *params, | |||
| 831 | if (phdr->p_vaddr >= seg->p_vaddr && | 836 | if (phdr->p_vaddr >= seg->p_vaddr && |
| 832 | phdr->p_vaddr + phdr->p_memsz <= | 837 | phdr->p_vaddr + phdr->p_memsz <= |
| 833 | seg->p_vaddr + seg->p_memsz) { | 838 | seg->p_vaddr + seg->p_memsz) { |
| 839 | Elf32_Dyn __user *dyn; | ||
| 840 | Elf32_Sword d_tag; | ||
| 841 | |||
| 834 | params->dynamic_addr = | 842 | params->dynamic_addr = |
| 835 | (phdr->p_vaddr - seg->p_vaddr) + | 843 | (phdr->p_vaddr - seg->p_vaddr) + |
| 836 | seg->addr; | 844 | seg->addr; |
| @@ -843,8 +851,9 @@ static int elf_fdpic_map_file(struct elf_fdpic_params *params, | |||
| 843 | goto dynamic_error; | 851 | goto dynamic_error; |
| 844 | 852 | ||
| 845 | tmp = phdr->p_memsz / sizeof(Elf32_Dyn); | 853 | tmp = phdr->p_memsz / sizeof(Elf32_Dyn); |
| 846 | if (((Elf32_Dyn *) | 854 | dyn = (Elf32_Dyn __user *)params->dynamic_addr; |
| 847 | params->dynamic_addr)[tmp - 1].d_tag != 0) | 855 | __get_user(d_tag, &dyn[tmp - 1].d_tag); |
| 856 | if (d_tag != 0) | ||
| 848 | goto dynamic_error; | 857 | goto dynamic_error; |
| 849 | break; | 858 | break; |
| 850 | } | 859 | } |
