]> bbs.cooldavid.org Git - net-next-2.6.git/commitdiff
Merge git://git.linaro.org/nico/arm_security into devel-stable
authorRussell King <rmk+kernel@arm.linux.org.uk>
Wed, 30 Jun 2010 10:00:01 +0000 (11:00 +0100)
committerRussell King <rmk+kernel@arm.linux.org.uk>
Wed, 30 Jun 2010 10:00:01 +0000 (11:00 +0100)
arch/arm/Kconfig
arch/arm/Makefile
arch/arm/include/asm/elf.h
arch/arm/include/asm/stackprotector.h [new file with mode: 0644]
arch/arm/kernel/asm-offsets.c
arch/arm/kernel/entry-armv.S
arch/arm/kernel/process.c
arch/arm/mm/mmap.c

index c171f35b73af3db2363fc52700778e8743ffb3ae..2244de273d2cf42a656bdc21820bba653255593a 100644 (file)
@@ -1375,6 +1375,18 @@ config UACCESS_WITH_MEMCPY
          However, if the CPU data cache is using a write-allocate mode,
          this option is unlikely to provide any performance gain.
 
+config CC_STACKPROTECTOR
+       bool "Enable -fstack-protector buffer overflow detection (EXPERIMENTAL)"
+       help
+         This option turns on the -fstack-protector GCC feature. This
+         feature puts, at the beginning of functions, a canary value on
+         the stack just before the return address, and validates
+         the value just before actually returning.  Stack based buffer
+         overflows (that need to overwrite this return address) now also
+         overwrite the canary, which gets detected and the attack is then
+         neutralized via a kernel panic.
+         This feature requires gcc version 4.2 or above.
+
 endmenu
 
 menu "Boot options"
index 64ba313724d2377fda7e439e130d7ad69dd1a83c..ddf6da158ad8a26870d158fb684063d66662bbd0 100644 (file)
@@ -34,6 +34,10 @@ ifeq ($(CONFIG_FRAME_POINTER),y)
 KBUILD_CFLAGS  +=-fno-omit-frame-pointer -mapcs -mno-sched-prolog
 endif
 
+ifeq ($(CONFIG_CC_STACKPROTECTOR),y)
+KBUILD_CFLAGS  +=-fstack-protector
+endif
+
 ifeq ($(CONFIG_CPU_BIG_ENDIAN),y)
 KBUILD_CPPFLAGS        += -mbig-endian
 AS             += -EB
index 51662feb9f1dd03b8e1c8a3f7d208c063208aa89..0a96e8c1b82ad515ca7eca45133abd0297925433 100644 (file)
@@ -121,4 +121,7 @@ int dump_task_regs(struct task_struct *t, elf_gregset_t *elfregs);
 extern void elf_set_personality(const struct elf32_hdr *);
 #define SET_PERSONALITY(ex)    elf_set_personality(&(ex))
 
+extern unsigned long arch_randomize_brk(struct mm_struct *mm);
+#define arch_randomize_brk arch_randomize_brk
+
 #endif
diff --git a/arch/arm/include/asm/stackprotector.h b/arch/arm/include/asm/stackprotector.h
new file mode 100644 (file)
index 0000000..de00332
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * GCC stack protector support.
+ *
+ * Stack protector works by putting predefined pattern at the start of
+ * the stack frame and verifying that it hasn't been overwritten when
+ * returning from the function.  The pattern is called stack canary
+ * and gcc expects it to be defined by a global variable called
+ * "__stack_chk_guard" on ARM.  This unfortunately means that on SMP
+ * we cannot have a different canary value per task.
+ */
+
+#ifndef _ASM_STACKPROTECTOR_H
+#define _ASM_STACKPROTECTOR_H 1
+
+#include <linux/random.h>
+#include <linux/version.h>
+
+extern unsigned long __stack_chk_guard;
+
+/*
+ * Initialize the stackprotector canary value.
+ *
+ * NOTE: this must only be called from functions that never return,
+ * and it must always be inlined.
+ */
+static __always_inline void boot_init_stack_canary(void)
+{
+       unsigned long canary;
+
+       /* Try to get a semi random initial value. */
+       get_random_bytes(&canary, sizeof(canary));
+       canary ^= LINUX_VERSION_CODE;
+
+       current->stack_canary = canary;
+       __stack_chk_guard = current->stack_canary;
+}
+
+#endif /* _ASM_STACKPROTECTOR_H */
index 883511522fca9e83be970c2611fd2ce5a1a75a41..85f2a019f77bc93b17e0c55bf60693d18a8e2ffa 100644 (file)
@@ -40,6 +40,9 @@
 int main(void)
 {
   DEFINE(TSK_ACTIVE_MM,                offsetof(struct task_struct, active_mm));
+#ifdef CONFIG_CC_STACKPROTECTOR
+  DEFINE(TSK_STACK_CANARY,     offsetof(struct task_struct, stack_canary));
+#endif
   BLANK();
   DEFINE(TI_FLAGS,             offsetof(struct thread_info, flags));
   DEFINE(TI_PREEMPT,           offsetof(struct thread_info, preempt_count));
index 7ee48e7f8f318a7b453e12849b60a6832bb85770..2d14081b26b1d91c4b66574022569baa197f1efc 100644 (file)
@@ -745,6 +745,11 @@ ENTRY(__switch_to)
        mov     r4, #0xffff0fff
        str     r3, [r4, #-15]                  @ TLS val at 0xffff0ff0
 #endif
+#if defined(CONFIG_CC_STACKPROTECTOR) && !defined(CONFIG_SMP)
+       ldr     r7, [r2, #TI_TASK]
+       ldr     r8, =__stack_chk_guard
+       ldr     r7, [r7, #TSK_STACK_CANARY]
+#endif
 #ifdef CONFIG_MMU
        mcr     p15, 0, r6, c3, c0, 0           @ Set domain register
 #endif
@@ -753,6 +758,9 @@ ENTRY(__switch_to)
        ldr     r0, =thread_notify_head
        mov     r1, #THREAD_NOTIFY_SWITCH
        bl      atomic_notifier_call_chain
+#if defined(CONFIG_CC_STACKPROTECTOR) && !defined(CONFIG_SMP)
+       str     r7, [r8]
+#endif
  THUMB(        mov     ip, r4                     )
        mov     r0, r5
  ARM(  ldmia   r4, {r4 - sl, fp, sp, pc}  )    @ Load all regs saved previously
index acf5e6fdb6dcbe991d7bed5d63c7a77f38c16e34..090ac9459da11662891d313cf0f998ff4e4f6f77 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/tick.h>
 #include <linux/utsname.h>
 #include <linux/uaccess.h>
+#include <linux/random.h>
 
 #include <asm/leds.h>
 #include <asm/processor.h>
 #include <asm/stacktrace.h>
 #include <asm/mach/time.h>
 
+#ifdef CONFIG_CC_STACKPROTECTOR
+#include <linux/stackprotector.h>
+unsigned long __stack_chk_guard __read_mostly;
+EXPORT_SYMBOL(__stack_chk_guard);
+#endif
+
 static const char *processor_modes[] = {
   "USER_26", "FIQ_26" , "IRQ_26" , "SVC_26" , "UK4_26" , "UK5_26" , "UK6_26" , "UK7_26" ,
   "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)
        } while (count ++ < 16);
        return 0;
 }
+
+unsigned long arch_randomize_brk(struct mm_struct *mm)
+{
+       unsigned long range_end = mm->brk + 0x02000000;
+       return randomize_range(mm->brk, range_end, 0) ? : mm->brk;
+}
index f5abc51c5a07ff24e047ef333c7dd47b942fc3a4..4f5b39687df541a417d4c3a9ac888fc53a31b999 100644 (file)
@@ -7,6 +7,7 @@
 #include <linux/shm.h>
 #include <linux/sched.h>
 #include <linux/io.h>
+#include <linux/random.h>
 #include <asm/cputype.h>
 #include <asm/system.h>
 
@@ -80,6 +81,9 @@ arch_get_unmapped_area(struct file *filp, unsigned long addr,
                start_addr = addr = TASK_UNMAPPED_BASE;
                mm->cached_hole_size = 0;
        }
+       /* 8 bits of randomness in 20 address space bits */
+       if (current->flags & PF_RANDOMIZE)
+               addr += (get_random_int() % (1 << 8)) << PAGE_SHIFT;
 
 full_search:
        if (do_align)