aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/x86/Kconfig3
-rw-r--r--arch/x86/include/asm/processor.h4
-rw-r--r--arch/x86/include/asm/segment.h9
-rw-r--r--arch/x86/include/asm/stackprotector.h91
-rw-r--r--arch/x86/include/asm/system.h21
-rw-r--r--arch/x86/kernel/Makefile18
-rw-r--r--arch/x86/kernel/cpu/common.c17
-rw-r--r--arch/x86/kernel/entry_32.S2
-rw-r--r--arch/x86/kernel/head_32.S20
-rw-r--r--arch/x86/kernel/process_32.c1
-rw-r--r--arch/x86/kernel/setup_percpu.c2
-rw-r--r--scripts/gcc-x86_32-has-stack-protector.sh8
12 files changed, 180 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
210config X86_32_LAZY_GS 210config 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
214config KTIME_SCALAR 214config KTIME_SCALAR
215 def_bool X86_32 215 def_bool X86_32
@@ -1356,7 +1356,6 @@ config CC_STACKPROTECTOR_ALL
1356 1356
1357config CC_STACKPROTECTOR 1357config 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);
396DECLARE_INIT_PER_CPU(irq_stack_union); 396DECLARE_INIT_PER_CPU(irq_stack_union);
397 397
398DECLARE_PER_CPU(char *, irq_stack_ptr); 398DECLARE_PER_CPU(char *, irq_stack_ptr);
399#else /* X86_64 */
400#ifdef CONFIG_CC_STACKPROTECTOR
401DECLARE_PER_CPU(unsigned long, stack_canary);
399#endif 402#endif
403#endif /* X86_64 */
400 404
401extern void print_cpu_info(struct cpuinfo_x86 *); 405extern void print_cpu_info(struct cpuinfo_x86 *);
402extern unsigned int xstate_size; 406extern 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
85static 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
100static 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
113static inline void setup_stack_canary_segment(int cpu)
114{ }
115
116static 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)
24CFLAGS_hpet.o := $(nostackp) 24CFLAGS_hpet.o := $(nostackp)
25CFLAGS_tsc.o := $(nostackp) 25CFLAGS_tsc.o := $(nostackp)
26CFLAGS_paravirt.o := $(nostackp) 26CFLAGS_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#
39ifdef CONFIG_X86_32
40CFLAGS_process_32.o := $(nostackp)
41CFLAGS_vm86_32.o := $(nostackp)
42CFLAGS_signal.o := $(nostackp)
43CFLAGS_traps.o := $(nostackp)
44endif
27 45
28obj-y := process_$(BITS).o signal.o entry_$(BITS).o 46obj-y := process_$(BITS).o signal.o entry_$(BITS).o
29obj-y += traps.o irq.o irq_$(BITS).o dumpstack_$(BITS).o 47obj-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} };
127EXPORT_PER_CPU_SYMBOL_GPL(gdt_page); 129EXPORT_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 */
947DEFINE_PER_CPU(struct orig_ist, orig_ist); 950DEFINE_PER_CPU(struct orig_ist, orig_ist);
948 951
949#else 952#else /* x86_64 */
953
954#ifdef CONFIG_CC_STACKPROTECTOR
955DEFINE_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 */
952struct pt_regs * __cpuinit idle_regs(struct pt_regs *regs) 959struct 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)
4541:
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
diff --git a/scripts/gcc-x86_32-has-stack-protector.sh b/scripts/gcc-x86_32-has-stack-protector.sh
new file mode 100644
index 000000000000..4fdf6ce1b062
--- /dev/null
+++ b/scripts/gcc-x86_32-has-stack-protector.sh
@@ -0,0 +1,8 @@
1#!/bin/sh
2
3echo "int foo(void) { char X[200]; return 3; }" | $1 -S -xc -c -O0 -fstack-protector - -o - 2> /dev/null | grep -q "%gs"
4if [ "$?" -eq "0" ] ; then
5 echo y
6else
7 echo n
8fi