]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/commitdiff
Merge branch 'linus' into stackprotector
authorIngo Molnar <mingo@elte.hu>
Wed, 25 Jun 2008 10:27:29 +0000 (12:27 +0200)
committerIngo Molnar <mingo@elte.hu>
Wed, 25 Jun 2008 10:27:29 +0000 (12:27 +0200)
17 files changed:
arch/x86/Kconfig
arch/x86/Kconfig.debug
arch/x86/Makefile
arch/x86/kernel/Makefile
arch/x86/kernel/process_64.c
arch/x86/mm/fault.c
include/asm-x86/pda.h
include/asm-x86/stackprotector.h [new file with mode: 0644]
include/asm-x86/system.h
include/linux/magic.h
include/linux/sched.h
include/linux/stackprotector.h [new file with mode: 0644]
init/main.c
kernel/exit.c
kernel/fork.c
kernel/panic.c
kernel/sched.c

index e0edaaa6920af63832979a04d4f525acafe64e8a..09a28a36ff266e8c29e67aeb9dbc8162f3348393 100644 (file)
@@ -1145,13 +1145,17 @@ config SECCOMP
 
          If unsure, say Y. Only embedded should say N here.
 
+config CC_STACKPROTECTOR_ALL
+       bool
+
 config CC_STACKPROTECTOR
        bool "Enable -fstack-protector buffer overflow detection (EXPERIMENTAL)"
-       depends on X86_64 && EXPERIMENTAL && BROKEN
+       depends on X86_64
+       select CC_STACKPROTECTOR_ALL
        help
-         This option turns on the -fstack-protector GCC feature. This
-         feature puts, at the beginning of critical functions, a canary
-         value on the stack just before the return address, and validates
+          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
@@ -1159,15 +1163,8 @@ config CC_STACKPROTECTOR
 
          This feature requires gcc version 4.2 or above, or a distribution
          gcc with the feature backported. Older versions are automatically
-         detected and for those versions, this configuration option is ignored.
-
-config CC_STACKPROTECTOR_ALL
-       bool "Use stack-protector for all functions"
-       depends on CC_STACKPROTECTOR
-       help
-         Normally, GCC only inserts the canary value protection for
-         functions that use large-ish on-stack buffers. By enabling
-         this option, GCC will be asked to do this for ALL functions.
+         detected and for those versions, this configuration option is
+         ignored. (and a warning is printed during bootup)
 
 source kernel/Kconfig.hz
 
index 18363374d51a9a57b39b6fb8d3f87a054b4b4aa5..a8d3c7e0414a3b3b2ba29f559a9b53061d81ad00 100644 (file)
@@ -106,6 +106,7 @@ config DIRECT_GBPAGES
 config DEBUG_RODATA_TEST
        bool "Testcase for the DEBUG_RODATA feature"
        depends on DEBUG_RODATA
+       default y
        help
          This option enables a testcase for the DEBUG_RODATA
          feature as well as for the change_page_attr() infrastructure.
index 3cff3c894cf3c0cd80161d1f61a959cbb80f7106..c3e0eeeb1dd2a5096b114593cfe4e0540ecd050d 100644 (file)
@@ -73,7 +73,7 @@ else
 
         stackp := $(CONFIG_SHELL) $(srctree)/scripts/gcc-x86_64-has-stack-protector.sh
         stackp-$(CONFIG_CC_STACKPROTECTOR) := $(shell $(stackp) \
-                "$(CC)" -fstack-protector )
+                "$(CC)" "-fstack-protector -DGCC_HAS_SP" )
         stackp-$(CONFIG_CC_STACKPROTECTOR_ALL) += $(shell $(stackp) \
                 "$(CC)" -fstack-protector-all )
 
index 77807d4769c99c455237a810fe0edd0f996fb31f..d001739d8b069d8b2d572c25aedfdef6b23a6472 100644 (file)
@@ -14,6 +14,7 @@ nostackp := $(call cc-option, -fno-stack-protector)
 CFLAGS_vsyscall_64.o   := $(PROFILING) -g0 $(nostackp)
 CFLAGS_hpet.o          := $(nostackp)
 CFLAGS_tsc_64.o                := $(nostackp)
+CFLAGS_paravirt.o      := $(nostackp)
 
 obj-y                  := process_$(BITS).o signal_$(BITS).o entry_$(BITS).o
 obj-y                  += traps_$(BITS).o irq_$(BITS).o
index c6eb5c91e5f607f7fb70758ed65eee667c7d1401..f73cfbc2c28133e58151fa4e83faf458b5c63944 100644 (file)
@@ -16,6 +16,7 @@
 
 #include <stdarg.h>
 
+#include <linux/stackprotector.h>
 #include <linux/cpu.h>
 #include <linux/errno.h>
 #include <linux/sched.h>
@@ -146,6 +147,17 @@ static inline void play_dead(void)
 void cpu_idle(void)
 {
        current_thread_info()->status |= TS_POLLING;
+
+       /*
+        * If we're the non-boot CPU, nothing set the PDA stack
+        * canary up for us - and if we are the boot CPU we have
+        * a 0 stack canary. This is a good place for updating
+        * it, as we wont ever return from this function (so the
+        * invalid canaries already on the stack wont ever
+        * trigger):
+        */
+       boot_init_stack_canary();
+
        /* endless idle loop with no priority at all */
        while (1) {
                tick_nohz_stop_sched_tick();
@@ -641,7 +653,6 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p)
        write_pda(kernelstack,
        (unsigned long)task_stack_page(next_p) + THREAD_SIZE - PDA_STACKOFFSET);
 #ifdef CONFIG_CC_STACKPROTECTOR
-       write_pda(stack_canary, next_p->stack_canary);
        /*
         * Build time only check to make sure the stack_canary is at
         * offset 40 in the pda; this is a gcc ABI requirement
index 8bcb6f40ccb6c61b762fac7def5c26a8eb01ba4b..0c5dcee23bb15cd93f8001e25b0e16eac22cfe63 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/kprobes.h>
 #include <linux/uaccess.h>
 #include <linux/kdebug.h>
+#include <linux/magic.h>
 
 #include <asm/system.h>
 #include <asm/desc.h>
@@ -586,6 +587,8 @@ void __kprobes do_page_fault(struct pt_regs *regs, unsigned long error_code)
        unsigned long address;
        int write, si_code;
        int fault;
+       unsigned long *stackend;
+
 #ifdef CONFIG_X86_64
        unsigned long flags;
 #endif
@@ -855,6 +858,10 @@ no_context:
 
        show_fault_oops(regs, error_code, address);
 
+       stackend = end_of_stack(tsk);
+       if (*stackend != STACK_END_MAGIC)
+               printk(KERN_ALERT "Thread overran stack, or stack corrupted\n");
+
        tsk->thread.cr2 = address;
        tsk->thread.trap_no = 14;
        tsk->thread.error_code = error_code;
index 101fb9e11954e8bd45c21a4524c5c8c8f9019132..62b734986a44a03ed3958b2d272d2124bec968e7 100644 (file)
@@ -16,11 +16,9 @@ struct x8664_pda {
        unsigned long oldrsp;           /* 24 user rsp for system call */
        int irqcount;                   /* 32 Irq nesting counter. Starts -1 */
        unsigned int cpunumber;         /* 36 Logical CPU number */
-#ifdef CONFIG_CC_STACKPROTECTOR
        unsigned long stack_canary;     /* 40 stack canary value */
                                        /* gcc-ABI: this canary MUST be at
                                           offset 40!!! */
-#endif
        char *irqstackptr;
        unsigned int __softirq_pending;
        unsigned int __nmi_count;       /* number of NMI on this CPUs */
diff --git a/include/asm-x86/stackprotector.h b/include/asm-x86/stackprotector.h
new file mode 100644 (file)
index 0000000..3baf7ad
--- /dev/null
@@ -0,0 +1,38 @@
+#ifndef _ASM_STACKPROTECTOR_H
+#define _ASM_STACKPROTECTOR_H 1
+
+#include <asm/tsc.h>
+
+/*
+ * 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)
+{
+       u64 canary;
+       u64 tsc;
+
+       /*
+        * If we're the non-boot CPU, nothing set the PDA stack
+        * canary up for us - and if we are the boot CPU we have
+        * a 0 stack canary. This is a good place for updating
+        * it, as we wont ever return from this function (so the
+        * invalid canaries already on the stack wont ever
+        * trigger).
+        *
+        * We both use the random pool and the current TSC as a source
+        * of randomness. The TSC only matters for very early init,
+        * there it already has some randomness on most systems. Later
+        * on during the bootup the random pool has true entropy too.
+        */
+       get_random_bytes(&canary, sizeof(canary));
+       tsc = __native_read_tsc();
+       canary += tsc + (tsc << 32UL);
+
+       current->stack_canary = canary;
+       write_pda(stack_canary, canary);
+}
+
+#endif
index a2f04cd79b29617e4677a0a1a1c23f4f1d434b23..172f54185093e9d02ae8101f47f4d1d26092a5f7 100644 (file)
@@ -92,6 +92,8 @@ do {                                                                  \
             ".globl thread_return\n"                                     \
             "thread_return:\n\t"                                         \
             "movq %%gs:%P[pda_pcurrent],%%rsi\n\t"                       \
+            "movq %P[task_canary](%%rsi),%%r8\n\t"                       \
+            "movq %%r8,%%gs:%P[pda_canary]\n\t"                          \
             "movq %P[thread_info](%%rsi),%%r8\n\t"                       \
             LOCK_PREFIX "btr  %[tif_fork],%P[ti_flags](%%r8)\n\t"        \
             "movq %%rax,%%rdi\n\t"                                       \
@@ -103,7 +105,9 @@ do {                                                                        \
               [ti_flags] "i" (offsetof(struct thread_info, flags)),      \
               [tif_fork] "i" (TIF_FORK),                                 \
               [thread_info] "i" (offsetof(struct task_struct, stack)),   \
-              [pda_pcurrent] "i" (offsetof(struct x8664_pda, pcurrent))  \
+              [task_canary] "i" (offsetof(struct task_struct, stack_canary)),\
+              [pda_pcurrent] "i" (offsetof(struct x8664_pda, pcurrent)), \
+              [pda_canary] "i" (offsetof(struct x8664_pda, stack_canary))\
             : "memory", "cc" __EXTRA_CLOBBER)
 #endif
 
index 1fa0c2ce4dec09456f5cb6c2480f6be5e5eb908a..74e68e201166c364095c85529eb5faa9ffe7ed07 100644 (file)
@@ -42,4 +42,5 @@
 #define FUTEXFS_SUPER_MAGIC    0xBAD1DEA
 #define INOTIFYFS_SUPER_MAGIC  0x2BAD1DEA
 
+#define STACK_END_MAGIC                0x57AC6E9D
 #endif /* __LINUX_MAGIC_H__ */
index c5d3f847ca8d05bd52ca575608c2d428a23d1b28..f0132f9ef4ddafb8f064a2af507042dde372c60c 100644 (file)
@@ -1095,10 +1095,9 @@ struct task_struct {
        pid_t pid;
        pid_t tgid;
 
-#ifdef CONFIG_CC_STACKPROTECTOR
        /* Canary value for the -fstack-protector gcc feature */
        unsigned long stack_canary;
-#endif
+
        /* 
         * pointers to (original) parent process, youngest child, younger sibling,
         * older sibling, respectively.  (p->father can be replaced with 
@@ -1971,6 +1970,19 @@ static inline unsigned long *end_of_stack(struct task_struct *p)
 
 extern void thread_info_cache_init(void);
 
+#ifdef CONFIG_DEBUG_STACK_USAGE
+static inline unsigned long stack_not_used(struct task_struct *p)
+{
+       unsigned long *n = end_of_stack(p);
+
+       do {    /* Skip over canary */
+               n++;
+       } while (!*n);
+
+       return (unsigned long)n - (unsigned long)end_of_stack(p);
+}
+#endif
+
 /* set thread flags in other task's structures
  * - see asm/thread_info.h for TIF_xxxx flags available
  */
diff --git a/include/linux/stackprotector.h b/include/linux/stackprotector.h
new file mode 100644 (file)
index 0000000..6f3e54c
--- /dev/null
@@ -0,0 +1,16 @@
+#ifndef _LINUX_STACKPROTECTOR_H
+#define _LINUX_STACKPROTECTOR_H 1
+
+#include <linux/compiler.h>
+#include <linux/sched.h>
+#include <linux/random.h>
+
+#ifdef CONFIG_CC_STACKPROTECTOR
+# include <asm/stackprotector.h>
+#else
+static inline void boot_init_stack_canary(void)
+{
+}
+#endif
+
+#endif
index f7fb20021d48d5a4a175cc79d84f6b3cfb9eab53..b44e4eb0f5e3d807044358db2ea4130ebeba724a 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/proc_fs.h>
 #include <linux/kernel.h>
 #include <linux/syscalls.h>
+#include <linux/stackprotector.h>
 #include <linux/string.h>
 #include <linux/ctype.h>
 #include <linux/delay.h>
@@ -545,6 +546,12 @@ asmlinkage void __init start_kernel(void)
        unwind_init();
        lockdep_init();
        debug_objects_early_init();
+
+       /*
+        * Set up the the initial canary ASAP:
+        */
+       boot_init_stack_canary();
+
        cgroup_init_early();
 
        local_irq_disable();
index 8f6185e69b691265746f81a1ca4ce9de9fd8a640..fb8de6cbf2c78dd6435239213594f1cdc9a4e28b 100644 (file)
@@ -899,12 +899,9 @@ static void check_stack_usage(void)
 {
        static DEFINE_SPINLOCK(low_water_lock);
        static int lowest_to_date = THREAD_SIZE;
-       unsigned long *n = end_of_stack(current);
        unsigned long free;
 
-       while (*n == 0)
-               n++;
-       free = (unsigned long)n - (unsigned long)end_of_stack(current);
+       free = stack_not_used(current);
 
        if (free >= lowest_to_date)
                return;
index 19908b26cf80494a0db8f3410384521081293a32..d428336e7aa13018814bd0106e1508e3d0c8dcc4 100644 (file)
@@ -54,6 +54,7 @@
 #include <linux/tty.h>
 #include <linux/proc_fs.h>
 #include <linux/blkdev.h>
+#include <linux/magic.h>
 
 #include <asm/pgtable.h>
 #include <asm/pgalloc.h>
@@ -186,6 +187,8 @@ static struct task_struct *dup_task_struct(struct task_struct *orig)
 {
        struct task_struct *tsk;
        struct thread_info *ti;
+       unsigned long *stackend;
+
        int err;
 
        prepare_to_copy(orig);
@@ -211,6 +214,8 @@ static struct task_struct *dup_task_struct(struct task_struct *orig)
                goto out;
 
        setup_thread_stack(tsk, orig);
+       stackend = end_of_stack(tsk);
+       *stackend = STACK_END_MAGIC;    /* for overflow detection */
 
 #ifdef CONFIG_CC_STACKPROTECTOR
        tsk->stack_canary = get_random_int();
index 425567f45b9f776148f1767b2f4af2d357a0c2fd..6729e3f4ebcb65d28b08f30c174f44f3a9734f67 100644 (file)
@@ -80,6 +80,9 @@ NORET_TYPE void panic(const char * fmt, ...)
        vsnprintf(buf, sizeof(buf), fmt, args);
        va_end(args);
        printk(KERN_EMERG "Kernel panic - not syncing: %s\n",buf);
+#ifdef CONFIG_DEBUG_BUGVERBOSE
+       dump_stack();
+#endif
        bust_spinlocks(0);
 
        /*
@@ -321,13 +324,85 @@ EXPORT_SYMBOL(warn_on_slowpath);
 #endif
 
 #ifdef CONFIG_CC_STACKPROTECTOR
+
+#ifndef GCC_HAS_SP
+#warning You have selected the CONFIG_CC_STACKPROTECTOR option, but the gcc used does not support this.
+#endif
+static unsigned long __stack_check_testing;
+/*
+ * Self test function for the stack-protector feature.
+ * This test requires that the local variable absolutely has
+ * a stack slot, hence the barrier()s.
+ */
+static noinline void __stack_chk_test_func(void)
+{
+       unsigned long foo;
+       barrier();
+       /*
+        * we need to make sure we're not about to clobber the return address,
+        * while real exploits do this, it's unhealthy on a running system.
+        * Besides, if we would, the test is already failed anyway so
+        * time to pull the emergency brake on it.
+        */
+       if ((unsigned long)__builtin_return_address(0) ==
+                                       *(((unsigned long *)&foo)+1)) {
+               printk(KERN_ERR "No -fstack-protector-stack-frame!\n");
+               return;
+       }
+#ifdef CONFIG_FRAME_POINTER
+       /* We also don't want to clobber the frame pointer */
+       if ((unsigned long)__builtin_return_address(0) ==
+                                       *(((unsigned long *)&foo)+2)) {
+               printk(KERN_ERR "No -fstack-protector-stack-frame!\n");
+               return;
+       }
+#endif
+       barrier();
+       if (current->stack_canary == *(((unsigned long *)&foo)+1))
+               *(((unsigned long *)&foo)+1) = 0;
+       else
+               printk(KERN_ERR "No -fstack-protector canary found\n");
+       barrier();
+}
+
+static int __stack_chk_test(void)
+{
+       printk(KERN_INFO "Testing -fstack-protector-all feature\n");
+       __stack_check_testing = (unsigned long)&__stack_chk_test_func;
+       __stack_chk_test_func();
+       if (__stack_check_testing) {
+               printk(KERN_ERR "-fstack-protector-all test failed\n");
+               WARN_ON(1);
+       }
+       return 0;
+}
 /*
  * Called when gcc's -fstack-protector feature is used, and
  * gcc detects corruption of the on-stack canary value
  */
 void __stack_chk_fail(void)
 {
-       panic("stack-protector: Kernel stack is corrupted");
+       if (__stack_check_testing == (unsigned long)&__stack_chk_test_func) {
+               long delta;
+
+               delta = (unsigned long)__builtin_return_address(0) -
+                               __stack_check_testing;
+               /*
+                * The test needs to happen inside the test function, so
+                * check if the return address is close to that function.
+                * The function is only 2 dozen bytes long, but keep a wide
+                * safety margin to avoid panic()s for normal users regardless
+                * of the quality of the compiler.
+                */
+               if (delta >= 0 && delta <= 400) {
+                       __stack_check_testing = 0;
+                       return;
+               }
+       }
+       panic("stack-protector: Kernel stack is corrupted in: %p\n",
+               __builtin_return_address(0));
 }
 EXPORT_SYMBOL(__stack_chk_fail);
+
+late_initcall(__stack_chk_test);
 #endif
index 3aaa5c8cb4214586bd283eedc2375baa3dc739c0..0cdb50260dbfbfac918e41bf20cdf3c8f395d33b 100644 (file)
@@ -5406,12 +5406,7 @@ void sched_show_task(struct task_struct *p)
                printk(KERN_CONT " %016lx ", thread_saved_pc(p));
 #endif
 #ifdef CONFIG_DEBUG_STACK_USAGE
-       {
-               unsigned long *n = end_of_stack(p);
-               while (!*n)
-                       n++;
-               free = (unsigned long)n - (unsigned long)end_of_stack(p);
-       }
+       free = stack_not_used(p);
 #endif
        printk(KERN_CONT "%5lu %5d %6d\n", free,
                task_pid_nr(p), task_pid_nr(p->real_parent));