diff options
author | Tejun Heo <tj@kernel.org> | 2009-02-09 08:17:40 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2009-02-09 18:42:01 -0500 |
commit | 60a5317ff0f42dd313094b88f809f63041568b08 (patch) | |
tree | 307dfd9715fbc9ff83c3c3ae3b0e8f03888083f2 /arch/x86 | |
parent | ccbeed3a05908d201b47b6c3dd1a373138bba566 (diff) |
x86: implement x86_32 stack protector
Impact: stack protector for x86_32
Implement stack protector for x86_32. GDT entry 28 is used for it.
It's set to point to stack_canary-20 and have the length of 24 bytes.
CONFIG_CC_STACKPROTECTOR turns off CONFIG_X86_32_LAZY_GS and sets %gs
to the stack canary segment on entry. As %gs is otherwise unused by
the kernel, the canary can be anywhere. It's defined as a percpu
variable.
x86_32 exception handlers take register frame on stack directly as
struct pt_regs. With -fstack-protector turned on, gcc copies the
whole structure after the stack canary and (of course) doesn't copy
back on return thus losing all changed. For now, -fno-stack-protector
is added to all files which contain those functions. We definitely
need something better.
Signed-off-by: Tejun Heo <tj@kernel.org>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'arch/x86')
-rw-r--r-- | arch/x86/Kconfig | 3 | ||||
-rw-r--r-- | arch/x86/include/asm/processor.h | 4 | ||||
-rw-r--r-- | arch/x86/include/asm/segment.h | 9 | ||||
-rw-r--r-- | arch/x86/include/asm/stackprotector.h | 91 | ||||
-rw-r--r-- | arch/x86/include/asm/system.h | 21 | ||||
-rw-r--r-- | arch/x86/kernel/Makefile | 18 | ||||
-rw-r--r-- | arch/x86/kernel/cpu/common.c | 17 | ||||
-rw-r--r-- | arch/x86/kernel/entry_32.S | 2 | ||||
-rw-r--r-- | arch/x86/kernel/head_32.S | 20 | ||||
-rw-r--r-- | arch/x86/kernel/process_32.c | 1 | ||||
-rw-r--r-- | arch/x86/kernel/setup_percpu.c | 2 |
11 files changed, 172 insertions, 16 deletions
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 5bcdede71ba4..f760a22f95dc 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig | |||
@@ -209,7 +209,7 @@ config X86_TRAMPOLINE | |||
209 | 209 | ||
210 | config X86_32_LAZY_GS | 210 | config X86_32_LAZY_GS |
211 | def_bool y | 211 | def_bool y |
212 | depends on X86_32 | 212 | depends on X86_32 && !CC_STACKPROTECTOR |
213 | 213 | ||
214 | config KTIME_SCALAR | 214 | config KTIME_SCALAR |
215 | def_bool X86_32 | 215 | def_bool X86_32 |
@@ -1356,7 +1356,6 @@ config CC_STACKPROTECTOR_ALL | |||
1356 | 1356 | ||
1357 | config CC_STACKPROTECTOR | 1357 | config CC_STACKPROTECTOR |
1358 | bool "Enable -fstack-protector buffer overflow detection (EXPERIMENTAL)" | 1358 | bool "Enable -fstack-protector buffer overflow detection (EXPERIMENTAL)" |
1359 | depends on X86_64 | ||
1360 | select CC_STACKPROTECTOR_ALL | 1359 | select CC_STACKPROTECTOR_ALL |
1361 | help | 1360 | help |
1362 | This option turns on the -fstack-protector GCC feature. This | 1361 | This option turns on the -fstack-protector GCC feature. This |
diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h index 9763eb700138..5a9472104253 100644 --- a/arch/x86/include/asm/processor.h +++ b/arch/x86/include/asm/processor.h | |||
@@ -396,7 +396,11 @@ DECLARE_PER_CPU(union irq_stack_union, irq_stack_union); | |||
396 | DECLARE_INIT_PER_CPU(irq_stack_union); | 396 | DECLARE_INIT_PER_CPU(irq_stack_union); |
397 | 397 | ||
398 | DECLARE_PER_CPU(char *, irq_stack_ptr); | 398 | DECLARE_PER_CPU(char *, irq_stack_ptr); |
399 | #else /* X86_64 */ | ||
400 | #ifdef CONFIG_CC_STACKPROTECTOR | ||
401 | DECLARE_PER_CPU(unsigned long, stack_canary); | ||
399 | #endif | 402 | #endif |
403 | #endif /* X86_64 */ | ||
400 | 404 | ||
401 | extern void print_cpu_info(struct cpuinfo_x86 *); | 405 | extern void print_cpu_info(struct cpuinfo_x86 *); |
402 | extern unsigned int xstate_size; | 406 | extern unsigned int xstate_size; |
diff --git a/arch/x86/include/asm/segment.h b/arch/x86/include/asm/segment.h index 1dc1b51ac623..14e0ed86a6f9 100644 --- a/arch/x86/include/asm/segment.h +++ b/arch/x86/include/asm/segment.h | |||
@@ -61,7 +61,7 @@ | |||
61 | * | 61 | * |
62 | * 26 - ESPFIX small SS | 62 | * 26 - ESPFIX small SS |
63 | * 27 - per-cpu [ offset to per-cpu data area ] | 63 | * 27 - per-cpu [ offset to per-cpu data area ] |
64 | * 28 - unused | 64 | * 28 - stack_canary-20 [ for stack protector ] |
65 | * 29 - unused | 65 | * 29 - unused |
66 | * 30 - unused | 66 | * 30 - unused |
67 | * 31 - TSS for double fault handler | 67 | * 31 - TSS for double fault handler |
@@ -95,6 +95,13 @@ | |||
95 | #define __KERNEL_PERCPU 0 | 95 | #define __KERNEL_PERCPU 0 |
96 | #endif | 96 | #endif |
97 | 97 | ||
98 | #define GDT_ENTRY_STACK_CANARY (GDT_ENTRY_KERNEL_BASE + 16) | ||
99 | #ifdef CONFIG_CC_STACKPROTECTOR | ||
100 | #define __KERNEL_STACK_CANARY (GDT_ENTRY_STACK_CANARY * 8) | ||
101 | #else | ||
102 | #define __KERNEL_STACK_CANARY 0 | ||
103 | #endif | ||
104 | |||
98 | #define GDT_ENTRY_DOUBLEFAULT_TSS 31 | 105 | #define GDT_ENTRY_DOUBLEFAULT_TSS 31 |
99 | 106 | ||
100 | /* | 107 | /* |
diff --git a/arch/x86/include/asm/stackprotector.h b/arch/x86/include/asm/stackprotector.h index ee275e9f48ab..fa7e5bd6fbe8 100644 --- a/arch/x86/include/asm/stackprotector.h +++ b/arch/x86/include/asm/stackprotector.h | |||
@@ -1,3 +1,35 @@ | |||
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 unfortunately gcc requires it to be at a fixed offset from %gs. | ||
8 | * On x86_64, the offset is 40 bytes and on x86_32 20 bytes. x86_64 | ||
9 | * and x86_32 use segment registers differently and thus handles this | ||
10 | * requirement differently. | ||
11 | * | ||
12 | * On x86_64, %gs is shared by percpu area and stack canary. All | ||
13 | * percpu symbols are zero based and %gs points to the base of percpu | ||
14 | * area. The first occupant of the percpu area is always | ||
15 | * irq_stack_union which contains stack_canary at offset 40. Userland | ||
16 | * %gs is always saved and restored on kernel entry and exit using | ||
17 | * swapgs, so stack protector doesn't add any complexity there. | ||
18 | * | ||
19 | * On x86_32, it's slightly more complicated. As in x86_64, %gs is | ||
20 | * used for userland TLS. Unfortunately, some processors are much | ||
21 | * slower at loading segment registers with different value when | ||
22 | * entering and leaving the kernel, so the kernel uses %fs for percpu | ||
23 | * area and manages %gs lazily so that %gs is switched only when | ||
24 | * necessary, usually during task switch. | ||
25 | * | ||
26 | * As gcc requires the stack canary at %gs:20, %gs can't be managed | ||
27 | * lazily if stack protector is enabled, so the kernel saves and | ||
28 | * restores userland %gs on kernel entry and exit. This behavior is | ||
29 | * controlled by CONFIG_X86_32_LAZY_GS and accessors are defined in | ||
30 | * system.h to hide the details. | ||
31 | */ | ||
32 | |||
1 | #ifndef _ASM_STACKPROTECTOR_H | 33 | #ifndef _ASM_STACKPROTECTOR_H |
2 | #define _ASM_STACKPROTECTOR_H 1 | 34 | #define _ASM_STACKPROTECTOR_H 1 |
3 | 35 | ||
@@ -6,9 +38,19 @@ | |||
6 | #include <asm/tsc.h> | 38 | #include <asm/tsc.h> |
7 | #include <asm/processor.h> | 39 | #include <asm/processor.h> |
8 | #include <asm/percpu.h> | 40 | #include <asm/percpu.h> |
41 | #include <asm/system.h> | ||
42 | #include <asm/desc.h> | ||
9 | #include <linux/random.h> | 43 | #include <linux/random.h> |
10 | 44 | ||
11 | /* | 45 | /* |
46 | * 24 byte read-only segment initializer for stack canary. Linker | ||
47 | * can't handle the address bit shifting. Address will be set in | ||
48 | * head_32 for boot CPU and setup_per_cpu_areas() for others. | ||
49 | */ | ||
50 | #define GDT_STACK_CANARY_INIT \ | ||
51 | [GDT_ENTRY_STACK_CANARY] = { { { 0x00000018, 0x00409000 } } }, | ||
52 | |||
53 | /* | ||
12 | * Initialize the stackprotector canary value. | 54 | * Initialize the stackprotector canary value. |
13 | * | 55 | * |
14 | * NOTE: this must only be called from functions that never return, | 56 | * NOTE: this must only be called from functions that never return, |
@@ -19,12 +61,9 @@ static __always_inline void boot_init_stack_canary(void) | |||
19 | u64 canary; | 61 | u64 canary; |
20 | u64 tsc; | 62 | u64 tsc; |
21 | 63 | ||
22 | /* | 64 | #ifdef CONFIG_X86_64 |
23 | * Build time only check to make sure the stack_canary is at | ||
24 | * offset 40 in the pda; this is a gcc ABI requirement | ||
25 | */ | ||
26 | BUILD_BUG_ON(offsetof(union irq_stack_union, stack_canary) != 40); | 65 | BUILD_BUG_ON(offsetof(union irq_stack_union, stack_canary) != 40); |
27 | 66 | #endif | |
28 | /* | 67 | /* |
29 | * We both use the random pool and the current TSC as a source | 68 | * We both use the random pool and the current TSC as a source |
30 | * of randomness. The TSC only matters for very early init, | 69 | * of randomness. The TSC only matters for very early init, |
@@ -36,7 +75,49 @@ static __always_inline void boot_init_stack_canary(void) | |||
36 | canary += tsc + (tsc << 32UL); | 75 | canary += tsc + (tsc << 32UL); |
37 | 76 | ||
38 | current->stack_canary = canary; | 77 | current->stack_canary = canary; |
78 | #ifdef CONFIG_X86_64 | ||
39 | percpu_write(irq_stack_union.stack_canary, canary); | 79 | percpu_write(irq_stack_union.stack_canary, canary); |
80 | #else | ||
81 | percpu_write(stack_canary, canary); | ||
82 | #endif | ||
83 | } | ||
84 | |||
85 | static inline void setup_stack_canary_segment(int cpu) | ||
86 | { | ||
87 | #ifdef CONFIG_X86_32 | ||
88 | unsigned long canary = (unsigned long)&per_cpu(stack_canary, cpu); | ||
89 | struct desc_struct *gdt_table = get_cpu_gdt_table(cpu); | ||
90 | struct desc_struct desc; | ||
91 | |||
92 | desc = gdt_table[GDT_ENTRY_STACK_CANARY]; | ||
93 | desc.base0 = canary & 0xffff; | ||
94 | desc.base1 = (canary >> 16) & 0xff; | ||
95 | desc.base2 = (canary >> 24) & 0xff; | ||
96 | write_gdt_entry(gdt_table, GDT_ENTRY_STACK_CANARY, &desc, DESCTYPE_S); | ||
97 | #endif | ||
98 | } | ||
99 | |||
100 | static inline void load_stack_canary_segment(void) | ||
101 | { | ||
102 | #ifdef CONFIG_X86_32 | ||
103 | asm("mov %0, %%gs" : : "r" (__KERNEL_STACK_CANARY) : "memory"); | ||
104 | #endif | ||
105 | } | ||
106 | |||
107 | #else /* CC_STACKPROTECTOR */ | ||
108 | |||
109 | #define GDT_STACK_CANARY_INIT | ||
110 | |||
111 | /* dummy boot_init_stack_canary() is defined in linux/stackprotector.h */ | ||
112 | |||
113 | static inline void setup_stack_canary_segment(int cpu) | ||
114 | { } | ||
115 | |||
116 | static inline void load_stack_canary_segment(void) | ||
117 | { | ||
118 | #ifdef CONFIG_X86_32 | ||
119 | asm volatile ("mov %0, %%gs" : : "r" (0)); | ||
120 | #endif | ||
40 | } | 121 | } |
41 | 122 | ||
42 | #endif /* CC_STACKPROTECTOR */ | 123 | #endif /* CC_STACKPROTECTOR */ |
diff --git a/arch/x86/include/asm/system.h b/arch/x86/include/asm/system.h index 79b98e5b96f4..2692ee8ef031 100644 --- a/arch/x86/include/asm/system.h +++ b/arch/x86/include/asm/system.h | |||
@@ -23,6 +23,22 @@ struct task_struct *__switch_to(struct task_struct *prev, | |||
23 | 23 | ||
24 | #ifdef CONFIG_X86_32 | 24 | #ifdef CONFIG_X86_32 |
25 | 25 | ||
26 | #ifdef CONFIG_CC_STACKPROTECTOR | ||
27 | #define __switch_canary \ | ||
28 | "movl "__percpu_arg([current_task])",%%ebx\n\t" \ | ||
29 | "movl %P[task_canary](%%ebx),%%ebx\n\t" \ | ||
30 | "movl %%ebx,"__percpu_arg([stack_canary])"\n\t" | ||
31 | #define __switch_canary_oparam \ | ||
32 | , [stack_canary] "=m" (per_cpu_var(stack_canary)) | ||
33 | #define __switch_canary_iparam \ | ||
34 | , [current_task] "m" (per_cpu_var(current_task)) \ | ||
35 | , [task_canary] "i" (offsetof(struct task_struct, stack_canary)) | ||
36 | #else /* CC_STACKPROTECTOR */ | ||
37 | #define __switch_canary | ||
38 | #define __switch_canary_oparam | ||
39 | #define __switch_canary_iparam | ||
40 | #endif /* CC_STACKPROTECTOR */ | ||
41 | |||
26 | /* | 42 | /* |
27 | * Saving eflags is important. It switches not only IOPL between tasks, | 43 | * Saving eflags is important. It switches not only IOPL between tasks, |
28 | * it also protects other tasks from NT leaking through sysenter etc. | 44 | * it also protects other tasks from NT leaking through sysenter etc. |
@@ -46,6 +62,7 @@ do { \ | |||
46 | "pushl %[next_ip]\n\t" /* restore EIP */ \ | 62 | "pushl %[next_ip]\n\t" /* restore EIP */ \ |
47 | "jmp __switch_to\n" /* regparm call */ \ | 63 | "jmp __switch_to\n" /* regparm call */ \ |
48 | "1:\t" \ | 64 | "1:\t" \ |
65 | __switch_canary \ | ||
49 | "popl %%ebp\n\t" /* restore EBP */ \ | 66 | "popl %%ebp\n\t" /* restore EBP */ \ |
50 | "popfl\n" /* restore flags */ \ | 67 | "popfl\n" /* restore flags */ \ |
51 | \ | 68 | \ |
@@ -58,6 +75,8 @@ do { \ | |||
58 | "=b" (ebx), "=c" (ecx), "=d" (edx), \ | 75 | "=b" (ebx), "=c" (ecx), "=d" (edx), \ |
59 | "=S" (esi), "=D" (edi) \ | 76 | "=S" (esi), "=D" (edi) \ |
60 | \ | 77 | \ |
78 | __switch_canary_oparam \ | ||
79 | \ | ||
61 | /* input parameters: */ \ | 80 | /* input parameters: */ \ |
62 | : [next_sp] "m" (next->thread.sp), \ | 81 | : [next_sp] "m" (next->thread.sp), \ |
63 | [next_ip] "m" (next->thread.ip), \ | 82 | [next_ip] "m" (next->thread.ip), \ |
@@ -66,6 +85,8 @@ do { \ | |||
66 | [prev] "a" (prev), \ | 85 | [prev] "a" (prev), \ |
67 | [next] "d" (next) \ | 86 | [next] "d" (next) \ |
68 | \ | 87 | \ |
88 | __switch_canary_iparam \ | ||
89 | \ | ||
69 | : /* reloaded segment registers */ \ | 90 | : /* reloaded segment registers */ \ |
70 | "memory"); \ | 91 | "memory"); \ |
71 | } while (0) | 92 | } while (0) |
diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile index 37fa30bada17..b1f8be33300d 100644 --- a/arch/x86/kernel/Makefile +++ b/arch/x86/kernel/Makefile | |||
@@ -24,6 +24,24 @@ 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 | CFLAGS_paravirt.o := $(nostackp) |
27 | # | ||
28 | # On x86_32, register frame is passed verbatim on stack as struct | ||
29 | # pt_regs. gcc considers the parameter to belong to the callee and | ||
30 | # with -fstack-protector it copies pt_regs to the callee's stack frame | ||
31 | # to put the structure after the stack canary causing changes made by | ||
32 | # the exception handlers to be lost. Turn off stack protector for all | ||
33 | # files containing functions which take struct pt_regs from register | ||
34 | # frame. | ||
35 | # | ||
36 | # The proper way to fix this is to teach gcc that the argument belongs | ||
37 | # to the caller for these functions, oh well... | ||
38 | # | ||
39 | ifdef CONFIG_X86_32 | ||
40 | CFLAGS_process_32.o := $(nostackp) | ||
41 | CFLAGS_vm86_32.o := $(nostackp) | ||
42 | CFLAGS_signal.o := $(nostackp) | ||
43 | CFLAGS_traps.o := $(nostackp) | ||
44 | endif | ||
27 | 45 | ||
28 | obj-y := process_$(BITS).o signal.o entry_$(BITS).o | 46 | obj-y := process_$(BITS).o signal.o entry_$(BITS).o |
29 | obj-y += traps.o irq.o irq_$(BITS).o dumpstack_$(BITS).o | 47 | obj-y += traps.o irq.o irq_$(BITS).o dumpstack_$(BITS).o |
diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c index 41b0de6df873..260fe4cb2c82 100644 --- a/arch/x86/kernel/cpu/common.c +++ b/arch/x86/kernel/cpu/common.c | |||
@@ -39,6 +39,7 @@ | |||
39 | #include <asm/sections.h> | 39 | #include <asm/sections.h> |
40 | #include <asm/setup.h> | 40 | #include <asm/setup.h> |
41 | #include <asm/hypervisor.h> | 41 | #include <asm/hypervisor.h> |
42 | #include <asm/stackprotector.h> | ||
42 | 43 | ||
43 | #include "cpu.h" | 44 | #include "cpu.h" |
44 | 45 | ||
@@ -122,6 +123,7 @@ DEFINE_PER_CPU_PAGE_ALIGNED(struct gdt_page, gdt_page) = { .gdt = { | |||
122 | 123 | ||
123 | [GDT_ENTRY_ESPFIX_SS] = { { { 0x00000000, 0x00c09200 } } }, | 124 | [GDT_ENTRY_ESPFIX_SS] = { { { 0x00000000, 0x00c09200 } } }, |
124 | [GDT_ENTRY_PERCPU] = { { { 0x0000ffff, 0x00cf9200 } } }, | 125 | [GDT_ENTRY_PERCPU] = { { { 0x0000ffff, 0x00cf9200 } } }, |
126 | GDT_STACK_CANARY_INIT | ||
125 | #endif | 127 | #endif |
126 | } }; | 128 | } }; |
127 | EXPORT_PER_CPU_SYMBOL_GPL(gdt_page); | 129 | EXPORT_PER_CPU_SYMBOL_GPL(gdt_page); |
@@ -261,6 +263,7 @@ void load_percpu_segment(int cpu) | |||
261 | loadsegment(gs, 0); | 263 | loadsegment(gs, 0); |
262 | wrmsrl(MSR_GS_BASE, (unsigned long)per_cpu(irq_stack_union.gs_base, cpu)); | 264 | wrmsrl(MSR_GS_BASE, (unsigned long)per_cpu(irq_stack_union.gs_base, cpu)); |
263 | #endif | 265 | #endif |
266 | load_stack_canary_segment(); | ||
264 | } | 267 | } |
265 | 268 | ||
266 | /* Current gdt points %fs at the "master" per-cpu area: after this, | 269 | /* Current gdt points %fs at the "master" per-cpu area: after this, |
@@ -946,16 +949,21 @@ unsigned long kernel_eflags; | |||
946 | */ | 949 | */ |
947 | DEFINE_PER_CPU(struct orig_ist, orig_ist); | 950 | DEFINE_PER_CPU(struct orig_ist, orig_ist); |
948 | 951 | ||
949 | #else | 952 | #else /* x86_64 */ |
953 | |||
954 | #ifdef CONFIG_CC_STACKPROTECTOR | ||
955 | DEFINE_PER_CPU(unsigned long, stack_canary); | ||
956 | #endif | ||
950 | 957 | ||
951 | /* Make sure %fs is initialized properly in idle threads */ | 958 | /* Make sure %fs and %gs are initialized properly in idle threads */ |
952 | struct pt_regs * __cpuinit idle_regs(struct pt_regs *regs) | 959 | struct pt_regs * __cpuinit idle_regs(struct pt_regs *regs) |
953 | { | 960 | { |
954 | memset(regs, 0, sizeof(struct pt_regs)); | 961 | memset(regs, 0, sizeof(struct pt_regs)); |
955 | regs->fs = __KERNEL_PERCPU; | 962 | regs->fs = __KERNEL_PERCPU; |
963 | regs->gs = __KERNEL_STACK_CANARY; | ||
956 | return regs; | 964 | return regs; |
957 | } | 965 | } |
958 | #endif | 966 | #endif /* x86_64 */ |
959 | 967 | ||
960 | /* | 968 | /* |
961 | * cpu_init() initializes state that is per-CPU. Some data is already | 969 | * cpu_init() initializes state that is per-CPU. Some data is already |
@@ -1120,9 +1128,6 @@ void __cpuinit cpu_init(void) | |||
1120 | __set_tss_desc(cpu, GDT_ENTRY_DOUBLEFAULT_TSS, &doublefault_tss); | 1128 | __set_tss_desc(cpu, GDT_ENTRY_DOUBLEFAULT_TSS, &doublefault_tss); |
1121 | #endif | 1129 | #endif |
1122 | 1130 | ||
1123 | /* Clear %gs. */ | ||
1124 | asm volatile ("mov %0, %%gs" : : "r" (0)); | ||
1125 | |||
1126 | /* Clear all 6 debug registers: */ | 1131 | /* Clear all 6 debug registers: */ |
1127 | set_debugreg(0, 0); | 1132 | set_debugreg(0, 0); |
1128 | set_debugreg(0, 1); | 1133 | set_debugreg(0, 1); |
diff --git a/arch/x86/kernel/entry_32.S b/arch/x86/kernel/entry_32.S index 82e6868bee47..5f5bd22adcd4 100644 --- a/arch/x86/kernel/entry_32.S +++ b/arch/x86/kernel/entry_32.S | |||
@@ -186,7 +186,7 @@ | |||
186 | /*CFI_REL_OFFSET gs, PT_GS*/ | 186 | /*CFI_REL_OFFSET gs, PT_GS*/ |
187 | .endm | 187 | .endm |
188 | .macro SET_KERNEL_GS reg | 188 | .macro SET_KERNEL_GS reg |
189 | xorl \reg, \reg | 189 | movl $(__KERNEL_STACK_CANARY), \reg |
190 | movl \reg, %gs | 190 | movl \reg, %gs |
191 | .endm | 191 | .endm |
192 | 192 | ||
diff --git a/arch/x86/kernel/head_32.S b/arch/x86/kernel/head_32.S index 24c0e5cd71e3..924e31615fb6 100644 --- a/arch/x86/kernel/head_32.S +++ b/arch/x86/kernel/head_32.S | |||
@@ -19,6 +19,7 @@ | |||
19 | #include <asm/asm-offsets.h> | 19 | #include <asm/asm-offsets.h> |
20 | #include <asm/setup.h> | 20 | #include <asm/setup.h> |
21 | #include <asm/processor-flags.h> | 21 | #include <asm/processor-flags.h> |
22 | #include <asm/percpu.h> | ||
22 | 23 | ||
23 | /* Physical address */ | 24 | /* Physical address */ |
24 | #define pa(X) ((X) - __PAGE_OFFSET) | 25 | #define pa(X) ((X) - __PAGE_OFFSET) |
@@ -437,8 +438,25 @@ is386: movl $2,%ecx # set MP | |||
437 | movl $(__KERNEL_PERCPU), %eax | 438 | movl $(__KERNEL_PERCPU), %eax |
438 | movl %eax,%fs # set this cpu's percpu | 439 | movl %eax,%fs # set this cpu's percpu |
439 | 440 | ||
440 | xorl %eax,%eax # Clear GS and LDT | 441 | #ifdef CONFIG_CC_STACKPROTECTOR |
442 | /* | ||
443 | * The linker can't handle this by relocation. Manually set | ||
444 | * base address in stack canary segment descriptor. | ||
445 | */ | ||
446 | cmpb $0,ready | ||
447 | jne 1f | ||
448 | movl $per_cpu__gdt_page,%eax | ||
449 | movl $per_cpu__stack_canary,%ecx | ||
450 | movw %cx, 8 * GDT_ENTRY_STACK_CANARY + 2(%eax) | ||
451 | shrl $16, %ecx | ||
452 | movb %cl, 8 * GDT_ENTRY_STACK_CANARY + 4(%eax) | ||
453 | movb %ch, 8 * GDT_ENTRY_STACK_CANARY + 7(%eax) | ||
454 | 1: | ||
455 | #endif | ||
456 | movl $(__KERNEL_STACK_CANARY),%eax | ||
441 | movl %eax,%gs | 457 | movl %eax,%gs |
458 | |||
459 | xorl %eax,%eax # Clear LDT | ||
442 | lldt %ax | 460 | lldt %ax |
443 | 461 | ||
444 | cld # gcc2 wants the direction flag cleared at all times | 462 | cld # gcc2 wants the direction flag cleared at all times |
diff --git a/arch/x86/kernel/process_32.c b/arch/x86/kernel/process_32.c index 86122fa2a1ba..9a62383e7c3c 100644 --- a/arch/x86/kernel/process_32.c +++ b/arch/x86/kernel/process_32.c | |||
@@ -212,6 +212,7 @@ int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags) | |||
212 | regs.ds = __USER_DS; | 212 | regs.ds = __USER_DS; |
213 | regs.es = __USER_DS; | 213 | regs.es = __USER_DS; |
214 | regs.fs = __KERNEL_PERCPU; | 214 | regs.fs = __KERNEL_PERCPU; |
215 | regs.gs = __KERNEL_STACK_CANARY; | ||
215 | regs.orig_ax = -1; | 216 | regs.orig_ax = -1; |
216 | regs.ip = (unsigned long) kernel_thread_helper; | 217 | regs.ip = (unsigned long) kernel_thread_helper; |
217 | regs.cs = __KERNEL_CS | get_kernel_rpl(); | 218 | regs.cs = __KERNEL_CS | get_kernel_rpl(); |
diff --git a/arch/x86/kernel/setup_percpu.c b/arch/x86/kernel/setup_percpu.c index ef91747bbed5..d992e6cff730 100644 --- a/arch/x86/kernel/setup_percpu.c +++ b/arch/x86/kernel/setup_percpu.c | |||
@@ -16,6 +16,7 @@ | |||
16 | #include <asm/proto.h> | 16 | #include <asm/proto.h> |
17 | #include <asm/cpumask.h> | 17 | #include <asm/cpumask.h> |
18 | #include <asm/cpu.h> | 18 | #include <asm/cpu.h> |
19 | #include <asm/stackprotector.h> | ||
19 | 20 | ||
20 | #ifdef CONFIG_DEBUG_PER_CPU_MAPS | 21 | #ifdef CONFIG_DEBUG_PER_CPU_MAPS |
21 | # define DBG(x...) printk(KERN_DEBUG x) | 22 | # define DBG(x...) printk(KERN_DEBUG x) |
@@ -95,6 +96,7 @@ void __init setup_per_cpu_areas(void) | |||
95 | per_cpu(this_cpu_off, cpu) = per_cpu_offset(cpu); | 96 | per_cpu(this_cpu_off, cpu) = per_cpu_offset(cpu); |
96 | per_cpu(cpu_number, cpu) = cpu; | 97 | per_cpu(cpu_number, cpu) = cpu; |
97 | setup_percpu_segment(cpu); | 98 | setup_percpu_segment(cpu); |
99 | setup_stack_canary_segment(cpu); | ||
98 | /* | 100 | /* |
99 | * Copy data used in early init routines from the | 101 | * Copy data used in early init routines from the |
100 | * initial arrays to the per cpu data areas. These | 102 | * initial arrays to the per cpu data areas. These |