diff options
author | Ingo Molnar <mingo@elte.hu> | 2009-01-19 06:36:09 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2009-01-19 06:36:09 -0500 |
commit | 7890ba8c87604ca4c2c73f7de846bf5305d743e4 (patch) | |
tree | f3f920c09b8de694b1bc1d4b878cfd2b0b98c913 /arch | |
parent | 99937d6455cea95405ac681c86a857d0fcd530bd (diff) | |
parent | b2b062b8163391c42b3219d466ca1ac9742b9c7b (diff) |
Merge branch 'stackprotector' into core/percpu
Diffstat (limited to 'arch')
-rw-r--r-- | arch/x86/Kconfig | 23 | ||||
-rw-r--r-- | arch/x86/Kconfig.debug | 1 | ||||
-rw-r--r-- | arch/x86/Makefile | 2 | ||||
-rw-r--r-- | arch/x86/include/asm/pda.h | 4 | ||||
-rw-r--r-- | arch/x86/include/asm/stackprotector.h | 39 | ||||
-rw-r--r-- | arch/x86/include/asm/system.h | 6 | ||||
-rw-r--r-- | arch/x86/kernel/Makefile | 1 | ||||
-rw-r--r-- | arch/x86/kernel/process_64.c | 13 | ||||
-rw-r--r-- | arch/x86/mm/fault.c | 7 |
9 files changed, 78 insertions, 18 deletions
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 73f7fe8fd4d1..ef27aed6ff74 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig | |||
@@ -1340,13 +1340,17 @@ config SECCOMP | |||
1340 | 1340 | ||
1341 | If unsure, say Y. Only embedded should say N here. | 1341 | If unsure, say Y. Only embedded should say N here. |
1342 | 1342 | ||
1343 | config CC_STACKPROTECTOR_ALL | ||
1344 | bool | ||
1345 | |||
1343 | config CC_STACKPROTECTOR | 1346 | config CC_STACKPROTECTOR |
1344 | bool "Enable -fstack-protector buffer overflow detection (EXPERIMENTAL)" | 1347 | bool "Enable -fstack-protector buffer overflow detection (EXPERIMENTAL)" |
1345 | depends on X86_64 && EXPERIMENTAL && BROKEN | 1348 | depends on X86_64 |
1349 | select CC_STACKPROTECTOR_ALL | ||
1346 | help | 1350 | help |
1347 | This option turns on the -fstack-protector GCC feature. This | 1351 | This option turns on the -fstack-protector GCC feature. This |
1348 | feature puts, at the beginning of critical functions, a canary | 1352 | feature puts, at the beginning of functions, a canary value on |
1349 | value on the stack just before the return address, and validates | 1353 | the stack just before the return address, and validates |
1350 | the value just before actually returning. Stack based buffer | 1354 | the value just before actually returning. Stack based buffer |
1351 | overflows (that need to overwrite this return address) now also | 1355 | overflows (that need to overwrite this return address) now also |
1352 | overwrite the canary, which gets detected and the attack is then | 1356 | overwrite the canary, which gets detected and the attack is then |
@@ -1354,15 +1358,8 @@ config CC_STACKPROTECTOR | |||
1354 | 1358 | ||
1355 | This feature requires gcc version 4.2 or above, or a distribution | 1359 | This feature requires gcc version 4.2 or above, or a distribution |
1356 | gcc with the feature backported. Older versions are automatically | 1360 | gcc with the feature backported. Older versions are automatically |
1357 | detected and for those versions, this configuration option is ignored. | 1361 | detected and for those versions, this configuration option is |
1358 | 1362 | ignored. (and a warning is printed during bootup) | |
1359 | config CC_STACKPROTECTOR_ALL | ||
1360 | bool "Use stack-protector for all functions" | ||
1361 | depends on CC_STACKPROTECTOR | ||
1362 | help | ||
1363 | Normally, GCC only inserts the canary value protection for | ||
1364 | functions that use large-ish on-stack buffers. By enabling | ||
1365 | this option, GCC will be asked to do this for ALL functions. | ||
1366 | 1363 | ||
1367 | source kernel/Kconfig.hz | 1364 | source kernel/Kconfig.hz |
1368 | 1365 | ||
diff --git a/arch/x86/Kconfig.debug b/arch/x86/Kconfig.debug index 10d6cc3fd052..28f111461ca8 100644 --- a/arch/x86/Kconfig.debug +++ b/arch/x86/Kconfig.debug | |||
@@ -117,6 +117,7 @@ config DEBUG_RODATA | |||
117 | config DEBUG_RODATA_TEST | 117 | config DEBUG_RODATA_TEST |
118 | bool "Testcase for the DEBUG_RODATA feature" | 118 | bool "Testcase for the DEBUG_RODATA feature" |
119 | depends on DEBUG_RODATA | 119 | depends on DEBUG_RODATA |
120 | default y | ||
120 | help | 121 | help |
121 | This option enables a testcase for the DEBUG_RODATA | 122 | This option enables a testcase for the DEBUG_RODATA |
122 | feature as well as for the change_page_attr() infrastructure. | 123 | feature as well as for the change_page_attr() infrastructure. |
diff --git a/arch/x86/Makefile b/arch/x86/Makefile index d1a47adb5aec..cacee981d166 100644 --- a/arch/x86/Makefile +++ b/arch/x86/Makefile | |||
@@ -73,7 +73,7 @@ else | |||
73 | 73 | ||
74 | stackp := $(CONFIG_SHELL) $(srctree)/scripts/gcc-x86_64-has-stack-protector.sh | 74 | stackp := $(CONFIG_SHELL) $(srctree)/scripts/gcc-x86_64-has-stack-protector.sh |
75 | stackp-$(CONFIG_CC_STACKPROTECTOR) := $(shell $(stackp) \ | 75 | stackp-$(CONFIG_CC_STACKPROTECTOR) := $(shell $(stackp) \ |
76 | "$(CC)" -fstack-protector ) | 76 | "$(CC)" "-fstack-protector -DGCC_HAS_SP" ) |
77 | stackp-$(CONFIG_CC_STACKPROTECTOR_ALL) += $(shell $(stackp) \ | 77 | stackp-$(CONFIG_CC_STACKPROTECTOR_ALL) += $(shell $(stackp) \ |
78 | "$(CC)" -fstack-protector-all ) | 78 | "$(CC)" -fstack-protector-all ) |
79 | 79 | ||
diff --git a/arch/x86/include/asm/pda.h b/arch/x86/include/asm/pda.h index c31ca048a901..5976cd803e9a 100644 --- a/arch/x86/include/asm/pda.h +++ b/arch/x86/include/asm/pda.h | |||
@@ -17,11 +17,9 @@ struct x8664_pda { | |||
17 | unsigned long unused4; | 17 | unsigned long unused4; |
18 | int unused5; | 18 | int unused5; |
19 | unsigned int unused6; /* 36 was cpunumber */ | 19 | unsigned int unused6; /* 36 was cpunumber */ |
20 | #ifdef CONFIG_CC_STACKPROTECTOR | ||
21 | unsigned long stack_canary; /* 40 stack canary value */ | 20 | unsigned long stack_canary; /* 40 stack canary value */ |
22 | /* gcc-ABI: this canary MUST be at | 21 | /* gcc-ABI: this canary MUST be at |
23 | offset 40!!! */ | 22 | offset 40!!! */ |
24 | #endif | ||
25 | short in_bootmem; /* pda lives in bootmem */ | 23 | short in_bootmem; /* pda lives in bootmem */ |
26 | } ____cacheline_aligned_in_smp; | 24 | } ____cacheline_aligned_in_smp; |
27 | 25 | ||
@@ -42,4 +40,6 @@ extern void pda_init(int); | |||
42 | 40 | ||
43 | #endif | 41 | #endif |
44 | 42 | ||
43 | #define refresh_stack_canary() write_pda(stack_canary, current->stack_canary) | ||
44 | |||
45 | #endif /* _ASM_X86_PDA_H */ | 45 | #endif /* _ASM_X86_PDA_H */ |
diff --git a/arch/x86/include/asm/stackprotector.h b/arch/x86/include/asm/stackprotector.h new file mode 100644 index 000000000000..c7f0d10bae7b --- /dev/null +++ b/arch/x86/include/asm/stackprotector.h | |||
@@ -0,0 +1,39 @@ | |||
1 | #ifndef _ASM_STACKPROTECTOR_H | ||
2 | #define _ASM_STACKPROTECTOR_H 1 | ||
3 | |||
4 | #include <asm/tsc.h> | ||
5 | #include <asm/pda.h> | ||
6 | |||
7 | /* | ||
8 | * Initialize the stackprotector canary value. | ||
9 | * | ||
10 | * NOTE: this must only be called from functions that never return, | ||
11 | * and it must always be inlined. | ||
12 | */ | ||
13 | static __always_inline void boot_init_stack_canary(void) | ||
14 | { | ||
15 | u64 canary; | ||
16 | u64 tsc; | ||
17 | |||
18 | /* | ||
19 | * If we're the non-boot CPU, nothing set the PDA stack | ||
20 | * canary up for us - and if we are the boot CPU we have | ||
21 | * a 0 stack canary. This is a good place for updating | ||
22 | * it, as we wont ever return from this function (so the | ||
23 | * invalid canaries already on the stack wont ever | ||
24 | * trigger). | ||
25 | * | ||
26 | * We both use the random pool and the current TSC as a source | ||
27 | * of randomness. The TSC only matters for very early init, | ||
28 | * there it already has some randomness on most systems. Later | ||
29 | * on during the bootup the random pool has true entropy too. | ||
30 | */ | ||
31 | get_random_bytes(&canary, sizeof(canary)); | ||
32 | tsc = __native_read_tsc(); | ||
33 | canary += tsc + (tsc << 32UL); | ||
34 | |||
35 | current->stack_canary = canary; | ||
36 | write_pda(stack_canary, canary); | ||
37 | } | ||
38 | |||
39 | #endif | ||
diff --git a/arch/x86/include/asm/system.h b/arch/x86/include/asm/system.h index d1dc27dba36d..8cadfe9b1194 100644 --- a/arch/x86/include/asm/system.h +++ b/arch/x86/include/asm/system.h | |||
@@ -95,6 +95,8 @@ do { \ | |||
95 | ".globl thread_return\n" \ | 95 | ".globl thread_return\n" \ |
96 | "thread_return:\n\t" \ | 96 | "thread_return:\n\t" \ |
97 | "movq "__percpu_arg([current_task])",%%rsi\n\t" \ | 97 | "movq "__percpu_arg([current_task])",%%rsi\n\t" \ |
98 | "movq %P[task_canary](%%rsi),%%r8\n\t" \ | ||
99 | "movq %%r8,%%gs:%P[pda_canary]\n\t" \ | ||
98 | "movq %P[thread_info](%%rsi),%%r8\n\t" \ | 100 | "movq %P[thread_info](%%rsi),%%r8\n\t" \ |
99 | LOCK_PREFIX "btr %[tif_fork],%P[ti_flags](%%r8)\n\t" \ | 101 | LOCK_PREFIX "btr %[tif_fork],%P[ti_flags](%%r8)\n\t" \ |
100 | "movq %%rax,%%rdi\n\t" \ | 102 | "movq %%rax,%%rdi\n\t" \ |
@@ -106,7 +108,9 @@ do { \ | |||
106 | [ti_flags] "i" (offsetof(struct thread_info, flags)), \ | 108 | [ti_flags] "i" (offsetof(struct thread_info, flags)), \ |
107 | [tif_fork] "i" (TIF_FORK), \ | 109 | [tif_fork] "i" (TIF_FORK), \ |
108 | [thread_info] "i" (offsetof(struct task_struct, stack)), \ | 110 | [thread_info] "i" (offsetof(struct task_struct, stack)), \ |
109 | [current_task] "m" (per_cpu_var(current_task)) \ | 111 | [task_canary] "i" (offsetof(struct task_struct, stack_canary)),\ |
112 | [current_task] "m" (per_cpu_var(current_task)), \ | ||
113 | [pda_canary] "i" (offsetof(struct x8664_pda, stack_canary))\ | ||
110 | : "memory", "cc" __EXTRA_CLOBBER) | 114 | : "memory", "cc" __EXTRA_CLOBBER) |
111 | #endif | 115 | #endif |
112 | 116 | ||
diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile index d364df03c1d6..eb074530c7d3 100644 --- a/arch/x86/kernel/Makefile +++ b/arch/x86/kernel/Makefile | |||
@@ -23,6 +23,7 @@ nostackp := $(call cc-option, -fno-stack-protector) | |||
23 | CFLAGS_vsyscall_64.o := $(PROFILING) -g0 $(nostackp) | 23 | CFLAGS_vsyscall_64.o := $(PROFILING) -g0 $(nostackp) |
24 | CFLAGS_hpet.o := $(nostackp) | 24 | CFLAGS_hpet.o := $(nostackp) |
25 | CFLAGS_tsc.o := $(nostackp) | 25 | CFLAGS_tsc.o := $(nostackp) |
26 | CFLAGS_paravirt.o := $(nostackp) | ||
26 | 27 | ||
27 | obj-y := process_$(BITS).o signal.o entry_$(BITS).o | 28 | obj-y := process_$(BITS).o signal.o entry_$(BITS).o |
28 | obj-y += traps.o irq.o irq_$(BITS).o dumpstack_$(BITS).o | 29 | obj-y += traps.o irq.o irq_$(BITS).o dumpstack_$(BITS).o |
diff --git a/arch/x86/kernel/process_64.c b/arch/x86/kernel/process_64.c index 4523ff88a69d..aa89eabf09e0 100644 --- a/arch/x86/kernel/process_64.c +++ b/arch/x86/kernel/process_64.c | |||
@@ -16,6 +16,7 @@ | |||
16 | 16 | ||
17 | #include <stdarg.h> | 17 | #include <stdarg.h> |
18 | 18 | ||
19 | #include <linux/stackprotector.h> | ||
19 | #include <linux/cpu.h> | 20 | #include <linux/cpu.h> |
20 | #include <linux/errno.h> | 21 | #include <linux/errno.h> |
21 | #include <linux/sched.h> | 22 | #include <linux/sched.h> |
@@ -117,6 +118,17 @@ static inline void play_dead(void) | |||
117 | void cpu_idle(void) | 118 | void cpu_idle(void) |
118 | { | 119 | { |
119 | current_thread_info()->status |= TS_POLLING; | 120 | current_thread_info()->status |= TS_POLLING; |
121 | |||
122 | /* | ||
123 | * If we're the non-boot CPU, nothing set the PDA stack | ||
124 | * canary up for us - and if we are the boot CPU we have | ||
125 | * a 0 stack canary. This is a good place for updating | ||
126 | * it, as we wont ever return from this function (so the | ||
127 | * invalid canaries already on the stack wont ever | ||
128 | * trigger): | ||
129 | */ | ||
130 | boot_init_stack_canary(); | ||
131 | |||
120 | /* endless idle loop with no priority at all */ | 132 | /* endless idle loop with no priority at all */ |
121 | while (1) { | 133 | while (1) { |
122 | tick_nohz_stop_sched_tick(1); | 134 | tick_nohz_stop_sched_tick(1); |
@@ -627,7 +639,6 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p) | |||
627 | (unsigned long)task_stack_page(next_p) + | 639 | (unsigned long)task_stack_page(next_p) + |
628 | THREAD_SIZE - KERNEL_STACK_OFFSET); | 640 | THREAD_SIZE - KERNEL_STACK_OFFSET); |
629 | #ifdef CONFIG_CC_STACKPROTECTOR | 641 | #ifdef CONFIG_CC_STACKPROTECTOR |
630 | write_pda(stack_canary, next_p->stack_canary); | ||
631 | /* | 642 | /* |
632 | * Build time only check to make sure the stack_canary is at | 643 | * Build time only check to make sure the stack_canary is at |
633 | * offset 40 in the pda; this is a gcc ABI requirement | 644 | * offset 40 in the pda; this is a gcc ABI requirement |
diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c index 90dfae511a41..37242c405f16 100644 --- a/arch/x86/mm/fault.c +++ b/arch/x86/mm/fault.c | |||
@@ -26,6 +26,7 @@ | |||
26 | #include <linux/kprobes.h> | 26 | #include <linux/kprobes.h> |
27 | #include <linux/uaccess.h> | 27 | #include <linux/uaccess.h> |
28 | #include <linux/kdebug.h> | 28 | #include <linux/kdebug.h> |
29 | #include <linux/magic.h> | ||
29 | 30 | ||
30 | #include <asm/system.h> | 31 | #include <asm/system.h> |
31 | #include <asm/desc.h> | 32 | #include <asm/desc.h> |
@@ -589,6 +590,8 @@ void __kprobes do_page_fault(struct pt_regs *regs, unsigned long error_code) | |||
589 | unsigned long address; | 590 | unsigned long address; |
590 | int write, si_code; | 591 | int write, si_code; |
591 | int fault; | 592 | int fault; |
593 | unsigned long *stackend; | ||
594 | |||
592 | #ifdef CONFIG_X86_64 | 595 | #ifdef CONFIG_X86_64 |
593 | unsigned long flags; | 596 | unsigned long flags; |
594 | int sig; | 597 | int sig; |
@@ -841,6 +844,10 @@ no_context: | |||
841 | 844 | ||
842 | show_fault_oops(regs, error_code, address); | 845 | show_fault_oops(regs, error_code, address); |
843 | 846 | ||
847 | stackend = end_of_stack(tsk); | ||
848 | if (*stackend != STACK_END_MAGIC) | ||
849 | printk(KERN_ALERT "Thread overran stack, or stack corrupted\n"); | ||
850 | |||
844 | tsk->thread.cr2 = address; | 851 | tsk->thread.cr2 = address; |
845 | tsk->thread.trap_no = 14; | 852 | tsk->thread.trap_no = 14; |
846 | tsk->thread.error_code = error_code; | 853 | tsk->thread.error_code = error_code; |