[ 007/102] ARM: move signal handlers into a vdso-like page
3.10-stable review patch. If anyone has any objections, please let me know. -- From: Russell King commit 48be69a026b2c17350a5ef18a1959a919f60be7d upstream. Move the signal handlers into a VDSO page rather than keeping them in the vectors page. This allows us to place them randomly within this page, and also map the page at a random location within userspace further protecting these code fragments from ROP attacks. The new VDSO page is also poisoned in the same way as the vector page. Signed-off-by: Russell King Signed-off-by: Greg Kroah-Hartman --- arch/arm/include/asm/elf.h |4 +++ arch/arm/include/asm/mmu.h |1 arch/arm/kernel/process.c | 40 +--- arch/arm/kernel/signal.c | 50 +++-- arch/arm/kernel/signal.h | 12 -- arch/arm/kernel/traps.c|9 6 files changed, 86 insertions(+), 30 deletions(-) --- a/arch/arm/include/asm/elf.h +++ b/arch/arm/include/asm/elf.h @@ -130,4 +130,8 @@ struct mm_struct; extern unsigned long arch_randomize_brk(struct mm_struct *mm); #define arch_randomize_brk arch_randomize_brk +#define ARCH_HAS_SETUP_ADDITIONAL_PAGES 1 +struct linux_binprm; +int arch_setup_additional_pages(struct linux_binprm *, int); + #endif --- a/arch/arm/include/asm/mmu.h +++ b/arch/arm/include/asm/mmu.h @@ -8,6 +8,7 @@ typedef struct { atomic64_t id; #endif unsigned intvmalloc_seq; + unsigned long sigpage; } mm_context_t; #ifdef CONFIG_CPU_HAS_ASID --- a/arch/arm/kernel/process.c +++ b/arch/arm/kernel/process.c @@ -435,8 +435,8 @@ unsigned long arch_randomize_brk(struct #ifdef CONFIG_MMU /* * The vectors page is always readable from user space for the - * atomic helpers and the signal restart code. Insert it into the - * gate_vma so that it is visible through ptrace and /proc//mem. + * atomic helpers. Insert it into the gate_vma so that it is visible + * through ptrace and /proc//mem. */ static struct vm_area_struct gate_vma = { .vm_start = 0x, @@ -468,6 +468,40 @@ int in_gate_area_no_mm(unsigned long add const char *arch_vma_name(struct vm_area_struct *vma) { - return (vma == _vma) ? "[vectors]" : NULL; + return (vma == _vma) ? "[vectors]" : + (vma->vm_mm && vma->vm_start == vma->vm_mm->context.sigpage) ? +"[sigpage]" : NULL; +} + +extern struct page *get_signal_page(void); + +int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp) +{ + struct mm_struct *mm = current->mm; + struct page *page; + unsigned long addr; + int ret; + + page = get_signal_page(); + if (!page) + return -ENOMEM; + + down_write(>mmap_sem); + addr = get_unmapped_area(NULL, 0, PAGE_SIZE, 0, 0); + if (IS_ERR_VALUE(addr)) { + ret = addr; + goto up_fail; + } + + ret = install_special_mapping(mm, addr, PAGE_SIZE, + VM_READ | VM_EXEC | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC, + ); + + if (ret == 0) + mm->context.sigpage = addr; + + up_fail: + up_write(>mmap_sem); + return ret; } #endif --- a/arch/arm/kernel/signal.c +++ b/arch/arm/kernel/signal.c @@ -8,6 +8,7 @@ * published by the Free Software Foundation. */ #include +#include #include #include #include @@ -15,12 +16,11 @@ #include #include +#include #include #include #include -#include "signal.h" - /* * For ARM syscalls, we encode the syscall number into the instruction. */ @@ -40,11 +40,13 @@ #define SWI_THUMB_SIGRETURN(0xdf00 << 16 | 0x2700 | (__NR_sigreturn - __NR_SYSCALL_BASE)) #define SWI_THUMB_RT_SIGRETURN (0xdf00 << 16 | 0x2700 | (__NR_rt_sigreturn - __NR_SYSCALL_BASE)) -const unsigned long sigreturn_codes[7] = { +static const unsigned long sigreturn_codes[7] = { MOV_R7_NR_SIGRETURN,SWI_SYS_SIGRETURN,SWI_THUMB_SIGRETURN, MOV_R7_NR_RT_SIGRETURN, SWI_SYS_RT_SIGRETURN, SWI_THUMB_RT_SIGRETURN, }; +static unsigned long signal_return_offset; + #ifdef CONFIG_CRUNCH static int preserve_crunch_context(struct crunch_sigframe __user *frame) { @@ -397,11 +399,14 @@ setup_return(struct pt_regs *regs, struc return 1; if (cpsr & MODE32_BIT) { + struct mm_struct *mm = current->mm; /* -* 32-bit code can use the new high-page -* signal return code support. +* 32-bit code can use the signal return page +* except when the MPU has protected the vectors +* page from PL0 */ - retcode = KERN_SIGRETURN_CODE + (idx << 2) + thumb; + retcode = mm->context.sigpage + signal_return_offset + +
[ 007/102] ARM: move signal handlers into a vdso-like page
3.10-stable review patch. If anyone has any objections, please let me know. -- From: Russell King rmk+ker...@arm.linux.org.uk commit 48be69a026b2c17350a5ef18a1959a919f60be7d upstream. Move the signal handlers into a VDSO page rather than keeping them in the vectors page. This allows us to place them randomly within this page, and also map the page at a random location within userspace further protecting these code fragments from ROP attacks. The new VDSO page is also poisoned in the same way as the vector page. Signed-off-by: Russell King rmk+ker...@arm.linux.org.uk Signed-off-by: Greg Kroah-Hartman gre...@linuxfoundation.org --- arch/arm/include/asm/elf.h |4 +++ arch/arm/include/asm/mmu.h |1 arch/arm/kernel/process.c | 40 +--- arch/arm/kernel/signal.c | 50 +++-- arch/arm/kernel/signal.h | 12 -- arch/arm/kernel/traps.c|9 6 files changed, 86 insertions(+), 30 deletions(-) --- a/arch/arm/include/asm/elf.h +++ b/arch/arm/include/asm/elf.h @@ -130,4 +130,8 @@ struct mm_struct; extern unsigned long arch_randomize_brk(struct mm_struct *mm); #define arch_randomize_brk arch_randomize_brk +#define ARCH_HAS_SETUP_ADDITIONAL_PAGES 1 +struct linux_binprm; +int arch_setup_additional_pages(struct linux_binprm *, int); + #endif --- a/arch/arm/include/asm/mmu.h +++ b/arch/arm/include/asm/mmu.h @@ -8,6 +8,7 @@ typedef struct { atomic64_t id; #endif unsigned intvmalloc_seq; + unsigned long sigpage; } mm_context_t; #ifdef CONFIG_CPU_HAS_ASID --- a/arch/arm/kernel/process.c +++ b/arch/arm/kernel/process.c @@ -435,8 +435,8 @@ unsigned long arch_randomize_brk(struct #ifdef CONFIG_MMU /* * The vectors page is always readable from user space for the - * atomic helpers and the signal restart code. Insert it into the - * gate_vma so that it is visible through ptrace and /proc/pid/mem. + * atomic helpers. Insert it into the gate_vma so that it is visible + * through ptrace and /proc/pid/mem. */ static struct vm_area_struct gate_vma = { .vm_start = 0x, @@ -468,6 +468,40 @@ int in_gate_area_no_mm(unsigned long add const char *arch_vma_name(struct vm_area_struct *vma) { - return (vma == gate_vma) ? [vectors] : NULL; + return (vma == gate_vma) ? [vectors] : + (vma-vm_mm vma-vm_start == vma-vm_mm-context.sigpage) ? +[sigpage] : NULL; +} + +extern struct page *get_signal_page(void); + +int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp) +{ + struct mm_struct *mm = current-mm; + struct page *page; + unsigned long addr; + int ret; + + page = get_signal_page(); + if (!page) + return -ENOMEM; + + down_write(mm-mmap_sem); + addr = get_unmapped_area(NULL, 0, PAGE_SIZE, 0, 0); + if (IS_ERR_VALUE(addr)) { + ret = addr; + goto up_fail; + } + + ret = install_special_mapping(mm, addr, PAGE_SIZE, + VM_READ | VM_EXEC | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC, + page); + + if (ret == 0) + mm-context.sigpage = addr; + + up_fail: + up_write(mm-mmap_sem); + return ret; } #endif --- a/arch/arm/kernel/signal.c +++ b/arch/arm/kernel/signal.c @@ -8,6 +8,7 @@ * published by the Free Software Foundation. */ #include linux/errno.h +#include linux/random.h #include linux/signal.h #include linux/personality.h #include linux/uaccess.h @@ -15,12 +16,11 @@ #include asm/elf.h #include asm/cacheflush.h +#include asm/traps.h #include asm/ucontext.h #include asm/unistd.h #include asm/vfp.h -#include signal.h - /* * For ARM syscalls, we encode the syscall number into the instruction. */ @@ -40,11 +40,13 @@ #define SWI_THUMB_SIGRETURN(0xdf00 16 | 0x2700 | (__NR_sigreturn - __NR_SYSCALL_BASE)) #define SWI_THUMB_RT_SIGRETURN (0xdf00 16 | 0x2700 | (__NR_rt_sigreturn - __NR_SYSCALL_BASE)) -const unsigned long sigreturn_codes[7] = { +static const unsigned long sigreturn_codes[7] = { MOV_R7_NR_SIGRETURN,SWI_SYS_SIGRETURN,SWI_THUMB_SIGRETURN, MOV_R7_NR_RT_SIGRETURN, SWI_SYS_RT_SIGRETURN, SWI_THUMB_RT_SIGRETURN, }; +static unsigned long signal_return_offset; + #ifdef CONFIG_CRUNCH static int preserve_crunch_context(struct crunch_sigframe __user *frame) { @@ -397,11 +399,14 @@ setup_return(struct pt_regs *regs, struc return 1; if (cpsr MODE32_BIT) { + struct mm_struct *mm = current-mm; /* -* 32-bit code can use the new high-page -* signal return code support. +* 32-bit code can use the signal return page +* except when the MPU has protected the vectors +* page