aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/kernel/signal.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/kernel/signal.c')
-rw-r--r--arch/arm/kernel/signal.c52
1 files changed, 45 insertions, 7 deletions
diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c
index 1c16c35c271a..0f17e06d51e6 100644
--- a/arch/arm/kernel/signal.c
+++ b/arch/arm/kernel/signal.c
@@ -8,6 +8,7 @@
8 * published by the Free Software Foundation. 8 * published by the Free Software Foundation.
9 */ 9 */
10#include <linux/errno.h> 10#include <linux/errno.h>
11#include <linux/random.h>
11#include <linux/signal.h> 12#include <linux/signal.h>
12#include <linux/personality.h> 13#include <linux/personality.h>
13#include <linux/uaccess.h> 14#include <linux/uaccess.h>
@@ -15,12 +16,11 @@
15 16
16#include <asm/elf.h> 17#include <asm/elf.h>
17#include <asm/cacheflush.h> 18#include <asm/cacheflush.h>
19#include <asm/traps.h>
18#include <asm/ucontext.h> 20#include <asm/ucontext.h>
19#include <asm/unistd.h> 21#include <asm/unistd.h>
20#include <asm/vfp.h> 22#include <asm/vfp.h>
21 23
22#include "signal.h"
23
24/* 24/*
25 * For ARM syscalls, we encode the syscall number into the instruction. 25 * For ARM syscalls, we encode the syscall number into the instruction.
26 */ 26 */
@@ -40,11 +40,13 @@
40#define SWI_THUMB_SIGRETURN (0xdf00 << 16 | 0x2700 | (__NR_sigreturn - __NR_SYSCALL_BASE)) 40#define SWI_THUMB_SIGRETURN (0xdf00 << 16 | 0x2700 | (__NR_sigreturn - __NR_SYSCALL_BASE))
41#define SWI_THUMB_RT_SIGRETURN (0xdf00 << 16 | 0x2700 | (__NR_rt_sigreturn - __NR_SYSCALL_BASE)) 41#define SWI_THUMB_RT_SIGRETURN (0xdf00 << 16 | 0x2700 | (__NR_rt_sigreturn - __NR_SYSCALL_BASE))
42 42
43const unsigned long sigreturn_codes[7] = { 43static const unsigned long sigreturn_codes[7] = {
44 MOV_R7_NR_SIGRETURN, SWI_SYS_SIGRETURN, SWI_THUMB_SIGRETURN, 44 MOV_R7_NR_SIGRETURN, SWI_SYS_SIGRETURN, SWI_THUMB_SIGRETURN,
45 MOV_R7_NR_RT_SIGRETURN, SWI_SYS_RT_SIGRETURN, SWI_THUMB_RT_SIGRETURN, 45 MOV_R7_NR_RT_SIGRETURN, SWI_SYS_RT_SIGRETURN, SWI_THUMB_RT_SIGRETURN,
46}; 46};
47 47
48static unsigned long signal_return_offset;
49
48#ifdef CONFIG_CRUNCH 50#ifdef CONFIG_CRUNCH
49static int preserve_crunch_context(struct crunch_sigframe __user *frame) 51static int preserve_crunch_context(struct crunch_sigframe __user *frame)
50{ 52{
@@ -401,12 +403,15 @@ setup_return(struct pt_regs *regs, struct ksignal *ksig,
401 return 1; 403 return 1;
402 404
403 if ((cpsr & MODE32_BIT) && !IS_ENABLED(CONFIG_ARM_MPU)) { 405 if ((cpsr & MODE32_BIT) && !IS_ENABLED(CONFIG_ARM_MPU)) {
406 struct mm_struct *mm = current->mm;
407
404 /* 408 /*
405 * 32-bit code can use the new high-page 409 * 32-bit code can use the signal return page
406 * signal return code support except when the MPU has 410 * except when the MPU has protected the vectors
407 * protected the vectors page from PL0 411 * page from PL0
408 */ 412 */
409 retcode = KERN_SIGRETURN_CODE + (idx << 2) + thumb; 413 retcode = mm->context.sigpage + signal_return_offset +
414 (idx << 2) + thumb;
410 } else { 415 } else {
411 /* 416 /*
412 * Ensure that the instruction cache sees 417 * Ensure that the instruction cache sees
@@ -608,3 +613,36 @@ do_work_pending(struct pt_regs *regs, unsigned int thread_flags, int syscall)
608 } while (thread_flags & _TIF_WORK_MASK); 613 } while (thread_flags & _TIF_WORK_MASK);
609 return 0; 614 return 0;
610} 615}
616
617static struct page *signal_page;
618
619struct page *get_signal_page(void)
620{
621 if (!signal_page) {
622 unsigned long ptr;
623 unsigned offset;
624 void *addr;
625
626 signal_page = alloc_pages(GFP_KERNEL, 0);
627
628 if (!signal_page)
629 return NULL;
630
631 addr = page_address(signal_page);
632
633 /* Give the signal return code some randomness */
634 offset = 0x200 + (get_random_int() & 0x7fc);
635 signal_return_offset = offset;
636
637 /*
638 * Copy signal return handlers into the vector page, and
639 * set sigreturn to be a pointer to these.
640 */
641 memcpy(addr + offset, sigreturn_codes, sizeof(sigreturn_codes));
642
643 ptr = (unsigned long)addr + offset;
644 flush_icache_range(ptr, ptr + sizeof(sigreturn_codes));
645 }
646
647 return signal_page;
648}