Skip to content

Commit 48be69a

Browse files
author
Russell King
committed
ARM: move signal handlers into a vdso-like page
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 <[email protected]>
1 parent f6f91b0 commit 48be69a

File tree

6 files changed

+87
-31
lines changed

6 files changed

+87
-31
lines changed

arch/arm/include/asm/elf.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,4 +130,8 @@ struct mm_struct;
130130
extern unsigned long arch_randomize_brk(struct mm_struct *mm);
131131
#define arch_randomize_brk arch_randomize_brk
132132

133+
#define ARCH_HAS_SETUP_ADDITIONAL_PAGES 1
134+
struct linux_binprm;
135+
int arch_setup_additional_pages(struct linux_binprm *, int);
136+
133137
#endif

arch/arm/include/asm/mmu.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ typedef struct {
88
atomic64_t id;
99
#endif
1010
unsigned int vmalloc_seq;
11+
unsigned long sigpage;
1112
} mm_context_t;
1213

1314
#ifdef CONFIG_CPU_HAS_ASID

arch/arm/kernel/process.c

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -428,8 +428,8 @@ unsigned long arch_randomize_brk(struct mm_struct *mm)
428428
#ifdef CONFIG_MMU
429429
/*
430430
* The vectors page is always readable from user space for the
431-
* atomic helpers and the signal restart code. Insert it into the
432-
* gate_vma so that it is visible through ptrace and /proc/<pid>/mem.
431+
* atomic helpers. Insert it into the gate_vma so that it is visible
432+
* through ptrace and /proc/<pid>/mem.
433433
*/
434434
static struct vm_area_struct gate_vma = {
435435
.vm_start = 0xffff0000,
@@ -461,6 +461,40 @@ int in_gate_area_no_mm(unsigned long addr)
461461

462462
const char *arch_vma_name(struct vm_area_struct *vma)
463463
{
464-
return (vma == &gate_vma) ? "[vectors]" : NULL;
464+
return (vma == &gate_vma) ? "[vectors]" :
465+
(vma->vm_mm && vma->vm_start == vma->vm_mm->context.sigpage) ?
466+
"[sigpage]" : NULL;
467+
}
468+
469+
extern struct page *get_signal_page(void);
470+
471+
int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
472+
{
473+
struct mm_struct *mm = current->mm;
474+
struct page *page;
475+
unsigned long addr;
476+
int ret;
477+
478+
page = get_signal_page();
479+
if (!page)
480+
return -ENOMEM;
481+
482+
down_write(&mm->mmap_sem);
483+
addr = get_unmapped_area(NULL, 0, PAGE_SIZE, 0, 0);
484+
if (IS_ERR_VALUE(addr)) {
485+
ret = addr;
486+
goto up_fail;
487+
}
488+
489+
ret = install_special_mapping(mm, addr, PAGE_SIZE,
490+
VM_READ | VM_EXEC | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC,
491+
&page);
492+
493+
if (ret == 0)
494+
mm->context.sigpage = addr;
495+
496+
up_fail:
497+
up_write(&mm->mmap_sem);
498+
return ret;
465499
}
466500
#endif

arch/arm/kernel/signal.c

Lines changed: 45 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,19 +8,19 @@
88
* published by the Free Software Foundation.
99
*/
1010
#include <linux/errno.h>
11+
#include <linux/random.h>
1112
#include <linux/signal.h>
1213
#include <linux/personality.h>
1314
#include <linux/uaccess.h>
1415
#include <linux/tracehook.h>
1516

1617
#include <asm/elf.h>
1718
#include <asm/cacheflush.h>
19+
#include <asm/traps.h>
1820
#include <asm/ucontext.h>
1921
#include <asm/unistd.h>
2022
#include <asm/vfp.h>
2123

22-
#include "signal.h"
23-
2424
/*
2525
* For ARM syscalls, we encode the syscall number into the instruction.
2626
*/
@@ -40,11 +40,13 @@
4040
#define SWI_THUMB_SIGRETURN (0xdf00 << 16 | 0x2700 | (__NR_sigreturn - __NR_SYSCALL_BASE))
4141
#define SWI_THUMB_RT_SIGRETURN (0xdf00 << 16 | 0x2700 | (__NR_rt_sigreturn - __NR_SYSCALL_BASE))
4242

43-
const unsigned long sigreturn_codes[7] = {
43+
static const unsigned long sigreturn_codes[7] = {
4444
MOV_R7_NR_SIGRETURN, SWI_SYS_SIGRETURN, SWI_THUMB_SIGRETURN,
4545
MOV_R7_NR_RT_SIGRETURN, SWI_SYS_RT_SIGRETURN, SWI_THUMB_RT_SIGRETURN,
4646
};
4747

48+
static unsigned long signal_return_offset;
49+
4850
#ifdef CONFIG_CRUNCH
4951
static int preserve_crunch_context(struct crunch_sigframe __user *frame)
5052
{
@@ -401,12 +403,15 @@ setup_return(struct pt_regs *regs, struct ksignal *ksig,
401403
return 1;
402404

403405
if ((cpsr & MODE32_BIT) && !IS_ENABLED(CONFIG_ARM_MPU)) {
406+
struct mm_struct *mm = current->mm;
407+
404408
/*
405-
* 32-bit code can use the new high-page
406-
* signal return code support except when the MPU has
407-
* protected the vectors page from PL0
409+
* 32-bit code can use the signal return page
410+
* except when the MPU has protected the vectors
411+
* page from PL0
408412
*/
409-
retcode = KERN_SIGRETURN_CODE + (idx << 2) + thumb;
413+
retcode = mm->context.sigpage + signal_return_offset +
414+
(idx << 2) + thumb;
410415
} else {
411416
/*
412417
* Ensure that the instruction cache sees
@@ -608,3 +613,36 @@ do_work_pending(struct pt_regs *regs, unsigned int thread_flags, int syscall)
608613
} while (thread_flags & _TIF_WORK_MASK);
609614
return 0;
610615
}
616+
617+
static struct page *signal_page;
618+
619+
struct 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+
}

arch/arm/kernel/signal.h

Lines changed: 0 additions & 12 deletions
This file was deleted.

arch/arm/kernel/traps.c

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,6 @@
3535
#include <asm/tls.h>
3636
#include <asm/system_misc.h>
3737

38-
#include "signal.h"
39-
4038
static const char *handler[]= { "prefetch abort", "data abort", "address exception", "interrupt" };
4139

4240
void *vectors_page;
@@ -850,13 +848,6 @@ void __init early_trap_init(void *vectors_base)
850848

851849
kuser_init(vectors_base);
852850

853-
/*
854-
* Copy signal return handlers into the vector page, and
855-
* set sigreturn to be a pointer to these.
856-
*/
857-
memcpy((void *)(vectors + KERN_SIGRETURN_CODE - CONFIG_VECTORS_BASE),
858-
sigreturn_codes, sizeof(sigreturn_codes));
859-
860851
flush_icache_range(vectors, vectors + PAGE_SIZE * 2);
861852
modify_domain(DOMAIN_USER, DOMAIN_CLIENT);
862853
#else /* ifndef CONFIG_CPU_V7M */

0 commit comments

Comments
 (0)