summaryrefslogtreecommitdiffstats
path: root/arch/arm
diff options
context:
space:
mode:
authorRussell King <rmk+kernel@armlinux.org.uk>2017-09-28 11:16:33 +0100
committerRussell King <rmk+kernel@armlinux.org.uk>2017-10-02 23:16:29 +0100
commit1bb078330b4f0836b5b12365cd8bf68d5f3bbff8 (patch)
tree0a15f41ace12c4b308ef6cc57e5aa3be0019e05d /arch/arm
parent476242482bdee72b30f188c2e025f0fa5df0208c (diff)
parentcdf38888ed30523b1a6ee199449a86dbd1d864ce (diff)
downloadtalos-obmc-linux-1bb078330b4f0836b5b12365cd8bf68d5f3bbff8.tar.gz
talos-obmc-linux-1bb078330b4f0836b5b12365cd8bf68d5f3bbff8.zip
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.
Diffstat (limited to 'arch/arm')
-rw-r--r--arch/arm/include/asm/elf.h16
-rw-r--r--arch/arm/include/asm/mmu.h8
-rw-r--r--arch/arm/include/asm/processor.h22
-rw-r--r--arch/arm/include/asm/ucontext.h1
-rw-r--r--arch/arm/include/uapi/asm/ptrace.h4
-rw-r--r--arch/arm/include/uapi/asm/unistd.h1
-rw-r--r--arch/arm/kernel/asm-offsets.c4
-rw-r--r--arch/arm/kernel/elf.c24
-rw-r--r--arch/arm/kernel/signal.c53
-rw-r--r--arch/arm/kernel/signal.h11
-rw-r--r--arch/arm/kernel/sigreturn_codes.S56
-rw-r--r--arch/arm/kernel/traps.c3
12 files changed, 173 insertions, 30 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;
extern int elf_check_arch(const struct elf32_hdr *);
#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)
-extern int arm_elf_read_implies_exec(const struct elf32_hdr *, int);
-#define elf_read_implies_exec(ex,stk) arm_elf_read_implies_exec(&(ex), stk)
+extern int arm_elf_read_implies_exec(int);
+#define elf_read_implies_exec(ex,stk) arm_elf_read_implies_exec(stk)
struct task_struct;
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. */
#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 *);
#define SET_PERSONALITY(ex) elf_set_personality(&(ex))
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 {
#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
@@ -33,6 +37,10 @@ typedef struct {
*/
typedef struct {
unsigned long end_brk;
+#ifdef CONFIG_BINFMT_ELF_FDPIC
+ unsigned long exec_fdpic_loadmap;
+ unsigned long interp_fdpic_loadmap;
+#endif
} mm_context_t;
#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 {
#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) \
({ \
+ 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)); \
+ 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) \
regs->ARM_cpsr = USR_MODE; \
else \
@@ -65,7 +74,6 @@ struct thread_struct {
regs->ARM_cpsr |= PSR_ENDSTATE; \
regs->ARM_pc = pc & ~1; /* pc */ \
regs->ARM_sp = sp; /* sp */ \
- nommu_start_thread(regs); \
})
/* 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 @@
#define _ASMARM_UCONTEXT_H
#include <asm/fpstate.h>
+#include <asm/user.h>
/*
* 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 @@
#define PTRACE_SETVFPREGS 28
#define PTRACE_GETHBPREGS 29
#define PTRACE_SETHBPREGS 30
+#define PTRACE_GETFDPIC 31
+
+#define PTRACE_GETFDPIC_EXEC 0
+#define PTRACE_GETFDPIC_INTERP 1
/*
* 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 @@
#define __ARM_NR_usr26 (__ARM_NR_BASE+3)
#define __ARM_NR_usr32 (__ARM_NR_BASE+4)
#define __ARM_NR_set_tls (__ARM_NR_BASE+5)
+#define __ARM_NR_get_tls (__ARM_NR_BASE+6)
#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 @@
#include <asm/vdso_datapage.h>
#include <asm/hardware/cache-l2x0.h>
#include <linux/kbuild.h>
+#include "signal.h"
/*
* Make sure that the compiler and target are compatible.
@@ -112,6 +113,9 @@ int main(void)
DEFINE(SVC_ADDR_LIMIT, offsetof(struct svc_pt_regs, addr_limit));
DEFINE(SVC_REGS_SIZE, sizeof(struct svc_pt_regs));
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
DEFINE(L2X0_R_PHY_BASE, offsetof(struct l2x0_regs, phy_base));
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 @@
#include <linux/personality.h>
#include <linux/binfmts.h>
#include <linux/elf.h>
+#include <linux/elf-fdpic.h>
#include <asm/system_info.h>
int elf_check_arch(const struct elf32_hdr *x)
@@ -80,7 +81,7 @@ EXPORT_SYMBOL(elf_set_personality);
* - the binary requires an executable stack
* - 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)
return 1;
@@ -89,3 +90,24 @@ int arm_elf_read_implies_exec(const struct elf32_hdr *x, 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/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 @@
#include <asm/elf.h>
#include <asm/cacheflush.h>
#include <asm/traps.h>
-#include <asm/ucontext.h>
#include <asm/unistd.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;
@@ -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.
*/
-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)
{
@@ -366,9 +358,20 @@ setup_return(struct pt_regs *regs, struct ksignal *ksig,
unsigned long __user *rc, void __user *frame)
{
unsigned long handler = (unsigned long)ksig->ka.sa.sa_handler;
+ unsigned long handler_fdpic_GOT = 0;
unsigned long retcode;
- int thumb = 0;
+ unsigned int idx, thumb = 0;
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;
@@ -408,9 +411,26 @@ setup_return(struct pt_regs *regs, struct ksignal *ksig,
if (ksig->ka.sa.sa_flags & 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 {
- unsigned int idx = thumb << 1;
-
+ idx = thumb << 1;
if (ksig->ka.sa.sa_flags & SA_SIGINFO)
idx += 3;
@@ -422,6 +442,7 @@ setup_return(struct pt_regs *regs, struct ksignal *ksig,
__put_user(sigreturn_codes[idx+1], rc+1))
return 1;
+rc_finish:
#ifdef CONFIG_MMU
if (cpsr & MODE32_BIT) {
struct mm_struct *mm = current->mm;
@@ -441,7 +462,7 @@ setup_return(struct pt_regs *regs, struct ksignal *ksig,
* the return code written onto the stack.
*/
flush_icache_range((unsigned long)rc,
- (unsigned long)(rc + 2));
+ (unsigned long)(rc + 3));
retcode = ((unsigned long)rc) + thumb;
}
@@ -451,6 +472,8 @@ setup_return(struct pt_regs *regs, struct ksignal *ksig,
regs->ARM_sp = (unsigned long)frame;
regs->ARM_lr = retcode;
regs->ARM_pc = handler;
+ if (fdpic)
+ regs->ARM_r9 = handler_fdpic_GOT;
regs->ARM_cpsr = cpsr;
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 @@
+#include <asm/ucontext.h>
+
+struct sigframe {
+ struct ucontext uc;
+ unsigned long retcode[4];
+};
+
+struct rt_sigframe {
+ struct siginfo info;
+ struct sigframe sig;
+};
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 @@
* GNU General Public License for more details.
*/
+#include <asm/assembler.h>
+#include <asm/asm-offsets.h>
#include <asm/unistd.h>
/*
@@ -51,6 +53,17 @@ ARM_OK( .arm )
.thumb
.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
/*
* Note we manually set minimally required arch that supports
@@ -90,13 +103,46 @@ ARM_OK( swi #(__NR_rt_sigreturn)|(__NR_OABI_SYSCALL_BASE) )
movs r7, #(__NR_rt_sigreturn - __NR_SYSCALL_BASE)
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
- * algorithm uses two words copy regardless whether
- * it is thumb case or not, so we need additional
- * word after real last entry.
+ * Note on additional space: setup_return in signal.c
+ * always copies the same number of words regardless whether
+ * it is thumb case or not, so we need one additional padding
+ * word after the last entry.
*/
- arm_slot 2
.space 4
.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)
set_tls(regs->ARM_r0);
return 0;
+ case NR(get_tls):
+ return current_thread_info()->tp_value[0];
+
default:
/* Calls 9f00xx..9f07ff are defined to return -ENOSYS
if not implemented, rather than raising SIGILL. This
OpenPOWER on IntegriCloud