aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorTejun Heo <tj@kernel.org>2009-02-11 02:31:00 -0500
committerIngo Molnar <mingo@elte.hu>2009-02-11 05:33:49 -0500
commit5c79d2a517a9905599d192db8ce77ab5f1a2faca (patch)
tree11f550a59b9b653fbd6c54b37effbf2d4a750fb5 /arch
parent60a5317ff0f42dd313094b88f809f63041568b08 (diff)
x86: fix x86_32 stack protector bugs
Impact: fix x86_32 stack protector Brian Gerst found out that %gs was being initialized to stack_canary instead of stack_canary - 20, which basically gave the same canary value for all threads. Fixing this also exposed the following bugs. * cpu_idle() didn't call boot_init_stack_canary() * stack canary switching in switch_to() was being done too late making the initial run of a new thread use the old stack canary value. Fix all of them and while at it update comment in cpu_idle() about calling boot_init_stack_canary(). Reported-by: Brian Gerst <brgerst@gmail.com> Signed-off-by: Tejun Heo <tj@kernel.org> Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'arch')
-rw-r--r--arch/x86/include/asm/stackprotector.h2
-rw-r--r--arch/x86/include/asm/system.h8
-rw-r--r--arch/x86/kernel/head_32.S1
-rw-r--r--arch/x86/kernel/process_32.c10
-rw-r--r--arch/x86/kernel/process_64.c11
5 files changed, 20 insertions, 12 deletions
diff --git a/arch/x86/include/asm/stackprotector.h b/arch/x86/include/asm/stackprotector.h
index fa7e5bd6fbe8..c2d742c6e15f 100644
--- a/arch/x86/include/asm/stackprotector.h
+++ b/arch/x86/include/asm/stackprotector.h
@@ -85,7 +85,7 @@ static __always_inline void boot_init_stack_canary(void)
85static inline void setup_stack_canary_segment(int cpu) 85static inline void setup_stack_canary_segment(int cpu)
86{ 86{
87#ifdef CONFIG_X86_32 87#ifdef CONFIG_X86_32
88 unsigned long canary = (unsigned long)&per_cpu(stack_canary, cpu); 88 unsigned long canary = (unsigned long)&per_cpu(stack_canary, cpu) - 20;
89 struct desc_struct *gdt_table = get_cpu_gdt_table(cpu); 89 struct desc_struct *gdt_table = get_cpu_gdt_table(cpu);
90 struct desc_struct desc; 90 struct desc_struct desc;
91 91
diff --git a/arch/x86/include/asm/system.h b/arch/x86/include/asm/system.h
index 2692ee8ef031..7a80f72bec47 100644
--- a/arch/x86/include/asm/system.h
+++ b/arch/x86/include/asm/system.h
@@ -25,13 +25,11 @@ struct task_struct *__switch_to(struct task_struct *prev,
25 25
26#ifdef CONFIG_CC_STACKPROTECTOR 26#ifdef CONFIG_CC_STACKPROTECTOR
27#define __switch_canary \ 27#define __switch_canary \
28 "movl "__percpu_arg([current_task])",%%ebx\n\t" \ 28 "movl %P[task_canary](%[next]), %%ebx\n\t" \
29 "movl %P[task_canary](%%ebx),%%ebx\n\t" \ 29 "movl %%ebx, "__percpu_arg([stack_canary])"\n\t"
30 "movl %%ebx,"__percpu_arg([stack_canary])"\n\t"
31#define __switch_canary_oparam \ 30#define __switch_canary_oparam \
32 , [stack_canary] "=m" (per_cpu_var(stack_canary)) 31 , [stack_canary] "=m" (per_cpu_var(stack_canary))
33#define __switch_canary_iparam \ 32#define __switch_canary_iparam \
34 , [current_task] "m" (per_cpu_var(current_task)) \
35 , [task_canary] "i" (offsetof(struct task_struct, stack_canary)) 33 , [task_canary] "i" (offsetof(struct task_struct, stack_canary))
36#else /* CC_STACKPROTECTOR */ 34#else /* CC_STACKPROTECTOR */
37#define __switch_canary 35#define __switch_canary
@@ -60,9 +58,9 @@ do { \
60 "movl %[next_sp],%%esp\n\t" /* restore ESP */ \ 58 "movl %[next_sp],%%esp\n\t" /* restore ESP */ \
61 "movl $1f,%[prev_ip]\n\t" /* save EIP */ \ 59 "movl $1f,%[prev_ip]\n\t" /* save EIP */ \
62 "pushl %[next_ip]\n\t" /* restore EIP */ \ 60 "pushl %[next_ip]\n\t" /* restore EIP */ \
61 __switch_canary \
63 "jmp __switch_to\n" /* regparm call */ \ 62 "jmp __switch_to\n" /* regparm call */ \
64 "1:\t" \ 63 "1:\t" \
65 __switch_canary \
66 "popl %%ebp\n\t" /* restore EBP */ \ 64 "popl %%ebp\n\t" /* restore EBP */ \
67 "popfl\n" /* restore flags */ \ 65 "popfl\n" /* restore flags */ \
68 \ 66 \
diff --git a/arch/x86/kernel/head_32.S b/arch/x86/kernel/head_32.S
index 924e31615fb6..cf21fd0cf6ac 100644
--- a/arch/x86/kernel/head_32.S
+++ b/arch/x86/kernel/head_32.S
@@ -447,6 +447,7 @@ is386: movl $2,%ecx # set MP
447 jne 1f 447 jne 1f
448 movl $per_cpu__gdt_page,%eax 448 movl $per_cpu__gdt_page,%eax
449 movl $per_cpu__stack_canary,%ecx 449 movl $per_cpu__stack_canary,%ecx
450 subl $20, %ecx
450 movw %cx, 8 * GDT_ENTRY_STACK_CANARY + 2(%eax) 451 movw %cx, 8 * GDT_ENTRY_STACK_CANARY + 2(%eax)
451 shrl $16, %ecx 452 shrl $16, %ecx
452 movb %cl, 8 * GDT_ENTRY_STACK_CANARY + 4(%eax) 453 movb %cl, 8 * GDT_ENTRY_STACK_CANARY + 4(%eax)
diff --git a/arch/x86/kernel/process_32.c b/arch/x86/kernel/process_32.c
index 9a62383e7c3c..b50604bb1e41 100644
--- a/arch/x86/kernel/process_32.c
+++ b/arch/x86/kernel/process_32.c
@@ -11,6 +11,7 @@
11 11
12#include <stdarg.h> 12#include <stdarg.h>
13 13
14#include <linux/stackprotector.h>
14#include <linux/cpu.h> 15#include <linux/cpu.h>
15#include <linux/errno.h> 16#include <linux/errno.h>
16#include <linux/sched.h> 17#include <linux/sched.h>
@@ -91,6 +92,15 @@ void cpu_idle(void)
91{ 92{
92 int cpu = smp_processor_id(); 93 int cpu = smp_processor_id();
93 94
95 /*
96 * If we're the non-boot CPU, nothing set the stack canary up
97 * for us. CPU0 already has it initialized but no harm in
98 * doing it again. This is a good place for updating it, as
99 * we wont ever return from this function (so the invalid
100 * canaries already on the stack wont ever trigger).
101 */
102 boot_init_stack_canary();
103
94 current_thread_info()->status |= TS_POLLING; 104 current_thread_info()->status |= TS_POLLING;
95 105
96 /* endless idle loop with no priority at all */ 106 /* endless idle loop with no priority at all */
diff --git a/arch/x86/kernel/process_64.c b/arch/x86/kernel/process_64.c
index 8eb169e45584..836ef6575f01 100644
--- a/arch/x86/kernel/process_64.c
+++ b/arch/x86/kernel/process_64.c
@@ -120,12 +120,11 @@ void cpu_idle(void)
120 current_thread_info()->status |= TS_POLLING; 120 current_thread_info()->status |= TS_POLLING;
121 121
122 /* 122 /*
123 * If we're the non-boot CPU, nothing set the PDA stack 123 * If we're the non-boot CPU, nothing set the stack canary up
124 * canary up for us - and if we are the boot CPU we have 124 * for us. CPU0 already has it initialized but no harm in
125 * a 0 stack canary. This is a good place for updating 125 * doing it again. This is a good place for updating it, as
126 * it, as we wont ever return from this function (so the 126 * we wont ever return from this function (so the invalid
127 * invalid canaries already on the stack wont ever 127 * canaries already on the stack wont ever trigger).
128 * trigger):
129 */ 128 */
130 boot_init_stack_canary(); 129 boot_init_stack_canary();
131 130