]> Pileus Git - ~andy/linux/commitdiff
Merge branch 'linus' into stackprotector
authorIngo Molnar <mingo@elte.hu>
Wed, 15 Oct 2008 11:46:29 +0000 (13:46 +0200)
committerIngo Molnar <mingo@elte.hu>
Wed, 15 Oct 2008 11:46:29 +0000 (13:46 +0200)
Conflicts:
arch/x86/kernel/Makefile
include/asm-x86/pda.h

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 f65c2744d5733971caf75b253070b4e9a821d786..e73ddc382a16c3724ade5037c78a9323215a6cf7 100644 (file)
@@ -1276,13 +1276,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
@@ -1290,15 +1294,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 2a3dfbd5e677b548e5e75f43da69e934b90a7eff..95fe606cb9a3599a993555f76d053717fa142b1d 100644 (file)
@@ -129,6 +129,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 f5631da585b69ac1722891bc0bee1e63a1ec652c..58ea55ce24238c8981e8fd1ec07ee6c19457593b 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 0d41f0343dc0753e5be4c97fd8b36460bc0ab2a5..50632e16d01c8b3f9c02b7519d0f6a16394cfeab 100644 (file)
@@ -21,6 +21,7 @@ nostackp := $(call cc-option, -fno-stack-protector)
 CFLAGS_vsyscall_64.o   := $(PROFILING) -g0 $(nostackp)
 CFLAGS_hpet.o          := $(nostackp)
 CFLAGS_tsc.o           := $(nostackp)
+CFLAGS_paravirt.o      := $(nostackp)
 
 obj-y                  := process_$(BITS).o signal_$(BITS).o entry_$(BITS).o
 obj-y                  += traps.o irq_$(BITS).o dumpstack_$(BITS).o
index cd8c0ed02b7e2c017905a403f10fc3cd25413f4a..749d5f888d4df3ebc07a4606684bd3f4054f1c23 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>
@@ -102,6 +103,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(1);
@@ -640,7 +652,6 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p)
                  (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 3f2b8962cbd0f71223ed8dfed8f90b893a966349..d18ea136d8a67567aabf8a0a9434ab0976fb2e89 100644 (file)
@@ -26,6 +26,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>
@@ -588,6 +589,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
@@ -850,6 +853,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 80860afffbdbbede4092bb18a6946e5b0a2831f9..45fd2aee8d6a7306f5967ef84d378c79f29ca6d8 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;
        short nodenumber;               /* number of current node (32k max) */
        short in_bootmem;               /* pda lives in bootmem */
@@ -134,4 +132,6 @@ do {                                                                        \
 
 #define PDA_STACKOFFSET (5*8)
 
+#define refresh_stack_canary() write_pda(stack_canary, current->stack_canary)
+
 #endif /* ASM_X86__PDA_H */
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 b20c894660f95ee1d056d86a238e2bb116cb673c..d79fa4a9ee64c916ef70315dade3b6064b045f80 100644 (file)
@@ -95,6 +95,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"                                       \
@@ -106,7 +108,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 f7f3fdddbef0b5f4f599cd506c524e4c9bf0b911..a07aa79593b7790c096f7973574bc8923201ba7b 100644 (file)
@@ -46,4 +46,5 @@
 #define FUTEXFS_SUPER_MAGIC    0xBAD1DEA
 #define INOTIFYFS_SUPER_MAGIC  0x2BAD1DEA
 
+#define STACK_END_MAGIC                0x57AC6E9D
 #endif /* __LINUX_MAGIC_H__ */
index c226c7b82946ce1d830853c4fd3b9bad3d92fa0d..1a7e8461db5a1174192933878476fe773fd6506c 100644 (file)
@@ -1094,10 +1094,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 
@@ -1974,6 +1973,19 @@ static inline int object_is_on_stack(void *obj)
 
 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 27f6bf6108e96908b10df5b20e0011aaebb3266c..6aaff34a38c01e9df7f08b83807734214b96d6ef 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>
@@ -550,6 +551,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 85a83c831856c193570e40a3b7d3e03ef8862d1c..c8d0485578be00a4d46b3b6823f161d0018b3778 100644 (file)
@@ -968,12 +968,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 30de644a40c4d4d9617d650589f4c90da1e977a2..99c5c655b098659ce4e410d77e58765b2d0d1075 100644 (file)
@@ -58,6 +58,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>
@@ -207,6 +208,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);
@@ -232,6 +235,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 12c5a0a6c89bee42e44c65ee41eb4695ae180983..e0a87bb025c00e4e0591db1c1f6b337c0f080a56 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);
 
        /*
@@ -343,13 +346,20 @@ EXPORT_SYMBOL(warn_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
+
 /*
  * 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");
+       panic("stack-protector: Kernel stack is corrupted in: %p\n",
+               __builtin_return_address(0));
 }
 EXPORT_SYMBOL(__stack_chk_fail);
+
 #endif
index 6f230596bd0c1d21a2c68ffbff8207e93dcd65b5..d897a524e7d8e5e88a96d1ab6b52f1e20d89fed3 100644 (file)
@@ -5790,12 +5790,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));