diff options
| -rw-r--r-- | arch/arm/Kconfig | 12 | ||||
| -rw-r--r-- | arch/arm/Makefile | 4 | ||||
| -rw-r--r-- | arch/arm/include/asm/elf.h | 3 | ||||
| -rw-r--r-- | arch/arm/include/asm/stackprotector.h | 38 | ||||
| -rw-r--r-- | arch/arm/kernel/asm-offsets.c | 3 | ||||
| -rw-r--r-- | arch/arm/kernel/entry-armv.S | 8 | ||||
| -rw-r--r-- | arch/arm/kernel/process.c | 13 | ||||
| -rw-r--r-- | arch/arm/mm/mmap.c | 4 |
8 files changed, 85 insertions, 0 deletions
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index c171f35b73af..2244de273d2c 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig | |||
| @@ -1375,6 +1375,18 @@ config UACCESS_WITH_MEMCPY | |||
| 1375 | However, if the CPU data cache is using a write-allocate mode, | 1375 | However, if the CPU data cache is using a write-allocate mode, |
| 1376 | this option is unlikely to provide any performance gain. | 1376 | this option is unlikely to provide any performance gain. |
| 1377 | 1377 | ||
| 1378 | config CC_STACKPROTECTOR | ||
| 1379 | bool "Enable -fstack-protector buffer overflow detection (EXPERIMENTAL)" | ||
| 1380 | help | ||
| 1381 | This option turns on the -fstack-protector GCC feature. This | ||
| 1382 | feature puts, at the beginning of functions, a canary value on | ||
| 1383 | the stack just before the return address, and validates | ||
| 1384 | the value just before actually returning. Stack based buffer | ||
| 1385 | overflows (that need to overwrite this return address) now also | ||
| 1386 | overwrite the canary, which gets detected and the attack is then | ||
| 1387 | neutralized via a kernel panic. | ||
| 1388 | This feature requires gcc version 4.2 or above. | ||
| 1389 | |||
| 1378 | endmenu | 1390 | endmenu |
| 1379 | 1391 | ||
| 1380 | menu "Boot options" | 1392 | menu "Boot options" |
diff --git a/arch/arm/Makefile b/arch/arm/Makefile index 64ba313724d2..ddf6da158ad8 100644 --- a/arch/arm/Makefile +++ b/arch/arm/Makefile | |||
| @@ -34,6 +34,10 @@ ifeq ($(CONFIG_FRAME_POINTER),y) | |||
| 34 | KBUILD_CFLAGS +=-fno-omit-frame-pointer -mapcs -mno-sched-prolog | 34 | KBUILD_CFLAGS +=-fno-omit-frame-pointer -mapcs -mno-sched-prolog |
| 35 | endif | 35 | endif |
| 36 | 36 | ||
| 37 | ifeq ($(CONFIG_CC_STACKPROTECTOR),y) | ||
| 38 | KBUILD_CFLAGS +=-fstack-protector | ||
| 39 | endif | ||
| 40 | |||
| 37 | ifeq ($(CONFIG_CPU_BIG_ENDIAN),y) | 41 | ifeq ($(CONFIG_CPU_BIG_ENDIAN),y) |
| 38 | KBUILD_CPPFLAGS += -mbig-endian | 42 | KBUILD_CPPFLAGS += -mbig-endian |
| 39 | AS += -EB | 43 | AS += -EB |
diff --git a/arch/arm/include/asm/elf.h b/arch/arm/include/asm/elf.h index 51662feb9f1d..0a96e8c1b82a 100644 --- a/arch/arm/include/asm/elf.h +++ b/arch/arm/include/asm/elf.h | |||
| @@ -121,4 +121,7 @@ int dump_task_regs(struct task_struct *t, elf_gregset_t *elfregs); | |||
| 121 | extern void elf_set_personality(const struct elf32_hdr *); | 121 | extern void elf_set_personality(const struct elf32_hdr *); |
| 122 | #define SET_PERSONALITY(ex) elf_set_personality(&(ex)) | 122 | #define SET_PERSONALITY(ex) elf_set_personality(&(ex)) |
| 123 | 123 | ||
| 124 | extern unsigned long arch_randomize_brk(struct mm_struct *mm); | ||
| 125 | #define arch_randomize_brk arch_randomize_brk | ||
| 126 | |||
| 124 | #endif | 127 | #endif |
diff --git a/arch/arm/include/asm/stackprotector.h b/arch/arm/include/asm/stackprotector.h new file mode 100644 index 000000000000..de003327be97 --- /dev/null +++ b/arch/arm/include/asm/stackprotector.h | |||
| @@ -0,0 +1,38 @@ | |||
| 1 | /* | ||
| 2 | * GCC stack protector support. | ||
| 3 | * | ||
| 4 | * Stack protector works by putting predefined pattern at the start of | ||
| 5 | * the stack frame and verifying that it hasn't been overwritten when | ||
| 6 | * returning from the function. The pattern is called stack canary | ||
| 7 | * and gcc expects it to be defined by a global variable called | ||
| 8 | * "__stack_chk_guard" on ARM. This unfortunately means that on SMP | ||
| 9 | * we cannot have a different canary value per task. | ||
| 10 | */ | ||
| 11 | |||
| 12 | #ifndef _ASM_STACKPROTECTOR_H | ||
| 13 | #define _ASM_STACKPROTECTOR_H 1 | ||
| 14 | |||
| 15 | #include <linux/random.h> | ||
| 16 | #include <linux/version.h> | ||
| 17 | |||
| 18 | extern unsigned long __stack_chk_guard; | ||
| 19 | |||
| 20 | /* | ||
| 21 | * Initialize the stackprotector canary value. | ||
| 22 | * | ||
| 23 | * NOTE: this must only be called from functions that never return, | ||
| 24 | * and it must always be inlined. | ||
| 25 | */ | ||
| 26 | static __always_inline void boot_init_stack_canary(void) | ||
| 27 | { | ||
| 28 | unsigned long canary; | ||
| 29 | |||
| 30 | /* Try to get a semi random initial value. */ | ||
| 31 | get_random_bytes(&canary, sizeof(canary)); | ||
| 32 | canary ^= LINUX_VERSION_CODE; | ||
| 33 | |||
| 34 | current->stack_canary = canary; | ||
| 35 | __stack_chk_guard = current->stack_canary; | ||
| 36 | } | ||
| 37 | |||
| 38 | #endif /* _ASM_STACKPROTECTOR_H */ | ||
diff --git a/arch/arm/kernel/asm-offsets.c b/arch/arm/kernel/asm-offsets.c index 883511522fca..85f2a019f77b 100644 --- a/arch/arm/kernel/asm-offsets.c +++ b/arch/arm/kernel/asm-offsets.c | |||
| @@ -40,6 +40,9 @@ | |||
| 40 | int main(void) | 40 | int main(void) |
| 41 | { | 41 | { |
| 42 | DEFINE(TSK_ACTIVE_MM, offsetof(struct task_struct, active_mm)); | 42 | DEFINE(TSK_ACTIVE_MM, offsetof(struct task_struct, active_mm)); |
| 43 | #ifdef CONFIG_CC_STACKPROTECTOR | ||
| 44 | DEFINE(TSK_STACK_CANARY, offsetof(struct task_struct, stack_canary)); | ||
| 45 | #endif | ||
| 43 | BLANK(); | 46 | BLANK(); |
| 44 | DEFINE(TI_FLAGS, offsetof(struct thread_info, flags)); | 47 | DEFINE(TI_FLAGS, offsetof(struct thread_info, flags)); |
| 45 | DEFINE(TI_PREEMPT, offsetof(struct thread_info, preempt_count)); | 48 | DEFINE(TI_PREEMPT, offsetof(struct thread_info, preempt_count)); |
diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S index 7ee48e7f8f31..2d14081b26b1 100644 --- a/arch/arm/kernel/entry-armv.S +++ b/arch/arm/kernel/entry-armv.S | |||
| @@ -745,6 +745,11 @@ ENTRY(__switch_to) | |||
| 745 | mov r4, #0xffff0fff | 745 | mov r4, #0xffff0fff |
| 746 | str r3, [r4, #-15] @ TLS val at 0xffff0ff0 | 746 | str r3, [r4, #-15] @ TLS val at 0xffff0ff0 |
| 747 | #endif | 747 | #endif |
| 748 | #if defined(CONFIG_CC_STACKPROTECTOR) && !defined(CONFIG_SMP) | ||
| 749 | ldr r7, [r2, #TI_TASK] | ||
| 750 | ldr r8, =__stack_chk_guard | ||
| 751 | ldr r7, [r7, #TSK_STACK_CANARY] | ||
| 752 | #endif | ||
| 748 | #ifdef CONFIG_MMU | 753 | #ifdef CONFIG_MMU |
| 749 | mcr p15, 0, r6, c3, c0, 0 @ Set domain register | 754 | mcr p15, 0, r6, c3, c0, 0 @ Set domain register |
| 750 | #endif | 755 | #endif |
| @@ -753,6 +758,9 @@ ENTRY(__switch_to) | |||
| 753 | ldr r0, =thread_notify_head | 758 | ldr r0, =thread_notify_head |
| 754 | mov r1, #THREAD_NOTIFY_SWITCH | 759 | mov r1, #THREAD_NOTIFY_SWITCH |
| 755 | bl atomic_notifier_call_chain | 760 | bl atomic_notifier_call_chain |
| 761 | #if defined(CONFIG_CC_STACKPROTECTOR) && !defined(CONFIG_SMP) | ||
| 762 | str r7, [r8] | ||
| 763 | #endif | ||
| 756 | THUMB( mov ip, r4 ) | 764 | THUMB( mov ip, r4 ) |
| 757 | mov r0, r5 | 765 | mov r0, r5 |
| 758 | ARM( ldmia r4, {r4 - sl, fp, sp, pc} ) @ Load all regs saved previously | 766 | ARM( ldmia r4, {r4 - sl, fp, sp, pc} ) @ Load all regs saved previously |
diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c index acf5e6fdb6dc..090ac9459da1 100644 --- a/arch/arm/kernel/process.c +++ b/arch/arm/kernel/process.c | |||
| @@ -28,6 +28,7 @@ | |||
| 28 | #include <linux/tick.h> | 28 | #include <linux/tick.h> |
| 29 | #include <linux/utsname.h> | 29 | #include <linux/utsname.h> |
| 30 | #include <linux/uaccess.h> | 30 | #include <linux/uaccess.h> |
| 31 | #include <linux/random.h> | ||
| 31 | 32 | ||
| 32 | #include <asm/leds.h> | 33 | #include <asm/leds.h> |
| 33 | #include <asm/processor.h> | 34 | #include <asm/processor.h> |
| @@ -36,6 +37,12 @@ | |||
| 36 | #include <asm/stacktrace.h> | 37 | #include <asm/stacktrace.h> |
| 37 | #include <asm/mach/time.h> | 38 | #include <asm/mach/time.h> |
| 38 | 39 | ||
| 40 | #ifdef CONFIG_CC_STACKPROTECTOR | ||
| 41 | #include <linux/stackprotector.h> | ||
| 42 | unsigned long __stack_chk_guard __read_mostly; | ||
| 43 | EXPORT_SYMBOL(__stack_chk_guard); | ||
| 44 | #endif | ||
| 45 | |||
| 39 | static const char *processor_modes[] = { | 46 | static const char *processor_modes[] = { |
| 40 | "USER_26", "FIQ_26" , "IRQ_26" , "SVC_26" , "UK4_26" , "UK5_26" , "UK6_26" , "UK7_26" , | 47 | "USER_26", "FIQ_26" , "IRQ_26" , "SVC_26" , "UK4_26" , "UK5_26" , "UK6_26" , "UK7_26" , |
| 41 | "UK8_26" , "UK9_26" , "UK10_26", "UK11_26", "UK12_26", "UK13_26", "UK14_26", "UK15_26", | 48 | "UK8_26" , "UK9_26" , "UK10_26", "UK11_26", "UK12_26", "UK13_26", "UK14_26", "UK15_26", |
| @@ -421,3 +428,9 @@ unsigned long get_wchan(struct task_struct *p) | |||
| 421 | } while (count ++ < 16); | 428 | } while (count ++ < 16); |
| 422 | return 0; | 429 | return 0; |
| 423 | } | 430 | } |
| 431 | |||
| 432 | unsigned long arch_randomize_brk(struct mm_struct *mm) | ||
| 433 | { | ||
| 434 | unsigned long range_end = mm->brk + 0x02000000; | ||
| 435 | return randomize_range(mm->brk, range_end, 0) ? : mm->brk; | ||
| 436 | } | ||
diff --git a/arch/arm/mm/mmap.c b/arch/arm/mm/mmap.c index f5abc51c5a07..4f5b39687df5 100644 --- a/arch/arm/mm/mmap.c +++ b/arch/arm/mm/mmap.c | |||
| @@ -7,6 +7,7 @@ | |||
| 7 | #include <linux/shm.h> | 7 | #include <linux/shm.h> |
| 8 | #include <linux/sched.h> | 8 | #include <linux/sched.h> |
| 9 | #include <linux/io.h> | 9 | #include <linux/io.h> |
| 10 | #include <linux/random.h> | ||
| 10 | #include <asm/cputype.h> | 11 | #include <asm/cputype.h> |
| 11 | #include <asm/system.h> | 12 | #include <asm/system.h> |
| 12 | 13 | ||
| @@ -80,6 +81,9 @@ arch_get_unmapped_area(struct file *filp, unsigned long addr, | |||
| 80 | start_addr = addr = TASK_UNMAPPED_BASE; | 81 | start_addr = addr = TASK_UNMAPPED_BASE; |
| 81 | mm->cached_hole_size = 0; | 82 | mm->cached_hole_size = 0; |
| 82 | } | 83 | } |
| 84 | /* 8 bits of randomness in 20 address space bits */ | ||
| 85 | if (current->flags & PF_RANDOMIZE) | ||
| 86 | addr += (get_random_int() % (1 << 8)) << PAGE_SHIFT; | ||
| 83 | 87 | ||
| 84 | full_search: | 88 | full_search: |
| 85 | if (do_align) | 89 | if (do_align) |
