Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

x86/stackprotector/64: Convert to normal per-CPU variable

Older versions of GCC fixed the location of the stack protector canary
at %gs:40. This constraint forced the percpu section to be linked at
absolute address 0 so that the canary could be the first data object in
the percpu section. Supporting the zero-based percpu section requires
additional code to handle relocations for RIP-relative references to
percpu data, extra complexity to kallsyms, and workarounds for linker
bugs due to the use of absolute symbols.

GCC 8.1 supports redefining where the canary is located, allowing it to
become a normal percpu variable instead of at a fixed location. This
removes the constraint that the percpu section must be zero-based.

Signed-off-by: Brian Gerst <brgerst@gmail.com>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Reviewed-by: Ard Biesheuvel <ardb@kernel.org>
Reviewed-by: Uros Bizjak <ubizjak@gmail.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Link: https://lore.kernel.org/r/20250123190747.745588-8-brgerst@gmail.com

authored by

Brian Gerst and committed by
Ingo Molnar
80d47def 78c4374e

+23 -70
+12 -8
arch/x86/Makefile
··· 140 140 # temporary until string.h is fixed 141 141 KBUILD_CFLAGS += -ffreestanding 142 142 143 - ifeq ($(CONFIG_STACKPROTECTOR),y) 144 - ifeq ($(CONFIG_SMP),y) 145 - KBUILD_CFLAGS += -mstack-protector-guard-reg=fs \ 146 - -mstack-protector-guard-symbol=__ref_stack_chk_guard 147 - else 148 - KBUILD_CFLAGS += -mstack-protector-guard=global 149 - endif 150 - endif 143 + percpu_seg := fs 151 144 else 152 145 BITS := 64 153 146 UTS_MACHINE := x86_64 ··· 190 197 KBUILD_CFLAGS += -mcmodel=kernel 191 198 KBUILD_RUSTFLAGS += -Cno-redzone=y 192 199 KBUILD_RUSTFLAGS += -Ccode-model=kernel 200 + 201 + percpu_seg := gs 202 + endif 203 + 204 + ifeq ($(CONFIG_STACKPROTECTOR),y) 205 + ifeq ($(CONFIG_SMP),y) 206 + KBUILD_CFLAGS += -mstack-protector-guard-reg=$(percpu_seg) 207 + KBUILD_CFLAGS += -mstack-protector-guard-symbol=__ref_stack_chk_guard 208 + else 209 + KBUILD_CFLAGS += -mstack-protector-guard=global 210 + endif 193 211 endif 194 212 195 213 #
-2
arch/x86/entry/entry.S
··· 52 52 53 53 THUNK warn_thunk_thunk, __warn_thunk 54 54 55 - #ifndef CONFIG_X86_64 56 55 /* 57 56 * Clang's implementation of TLS stack cookies requires the variable in 58 57 * question to be a TLS variable. If the variable happens to be defined as an ··· 64 65 */ 65 66 #ifdef CONFIG_STACKPROTECTOR 66 67 EXPORT_SYMBOL(__ref_stack_chk_guard); 67 - #endif 68 68 #endif
+1 -1
arch/x86/entry/entry_64.S
··· 192 192 193 193 #ifdef CONFIG_STACKPROTECTOR 194 194 movq TASK_stack_canary(%rsi), %rbx 195 - movq %rbx, PER_CPU_VAR(fixed_percpu_data + FIXED_stack_canary) 195 + movq %rbx, PER_CPU_VAR(__stack_chk_guard) 196 196 #endif 197 197 198 198 /*
+2 -14
arch/x86/include/asm/processor.h
··· 422 422 423 423 #ifdef CONFIG_X86_64 424 424 struct fixed_percpu_data { 425 - /* 426 - * GCC hardcodes the stack canary as %gs:40. Since the 427 - * irq_stack is the object at %gs:0, we reserve the bottom 428 - * 48 bytes of the irq stack for the canary. 429 - * 430 - * Once we are willing to require -mstack-protector-guard-symbol= 431 - * support for x86_64 stackprotector, we can get rid of this. 432 - */ 433 425 char gs_base[40]; 434 - unsigned long stack_canary; 426 + unsigned long reserved; 435 427 }; 436 428 437 429 DECLARE_PER_CPU_FIRST(struct fixed_percpu_data, fixed_percpu_data) __visible; ··· 438 446 439 447 /* Save actual FS/GS selectors and bases to current->thread */ 440 448 void current_save_fsgs(void); 441 - #else /* X86_64 */ 442 - #ifdef CONFIG_STACKPROTECTOR 443 - DECLARE_PER_CPU(unsigned long, __stack_chk_guard); 444 - #endif 445 - #endif /* !X86_64 */ 449 + #endif /* X86_64 */ 446 450 447 451 struct perf_event; 448 452
+5 -31
arch/x86/include/asm/stackprotector.h
··· 2 2 /* 3 3 * GCC stack protector support. 4 4 * 5 - * Stack protector works by putting predefined pattern at the start of 5 + * Stack protector works by putting a predefined pattern at the start of 6 6 * the stack frame and verifying that it hasn't been overwritten when 7 - * returning from the function. The pattern is called stack canary 8 - * and unfortunately gcc historically required it to be at a fixed offset 9 - * from the percpu segment base. On x86_64, the offset is 40 bytes. 10 - * 11 - * The same segment is shared by percpu area and stack canary. On 12 - * x86_64, percpu symbols are zero based and %gs (64-bit) points to the 13 - * base of percpu area. The first occupant of the percpu area is always 14 - * fixed_percpu_data which contains stack_canary at the appropriate 15 - * offset. On x86_32, the stack canary is just a regular percpu 16 - * variable. 17 - * 18 - * Putting percpu data in %fs on 32-bit is a minor optimization compared to 19 - * using %gs. Since 32-bit userspace normally has %fs == 0, we are likely 20 - * to load 0 into %fs on exit to usermode, whereas with percpu data in 21 - * %gs, we are likely to load a non-null %gs on return to user mode. 22 - * 23 - * Once we are willing to require GCC 8.1 or better for 64-bit stackprotector 24 - * support, we can remove some of this complexity. 7 + * returning from the function. The pattern is called the stack canary 8 + * and is a unique value for each task. 25 9 */ 26 10 27 11 #ifndef _ASM_STACKPROTECTOR_H ··· 19 35 #include <asm/desc.h> 20 36 21 37 #include <linux/sched.h> 38 + 39 + DECLARE_PER_CPU(unsigned long, __stack_chk_guard); 22 40 23 41 /* 24 42 * Initialize the stackprotector canary value. ··· 37 51 { 38 52 unsigned long canary = get_random_canary(); 39 53 40 - #ifdef CONFIG_X86_64 41 - BUILD_BUG_ON(offsetof(struct fixed_percpu_data, stack_canary) != 40); 42 - #endif 43 - 44 54 current->stack_canary = canary; 45 - #ifdef CONFIG_X86_64 46 - this_cpu_write(fixed_percpu_data.stack_canary, canary); 47 - #else 48 55 this_cpu_write(__stack_chk_guard, canary); 49 - #endif 50 56 } 51 57 52 58 static inline void cpu_init_stack_canary(int cpu, struct task_struct *idle) 53 59 { 54 - #ifdef CONFIG_X86_64 55 - per_cpu(fixed_percpu_data.stack_canary, cpu) = idle->stack_canary; 56 - #else 57 60 per_cpu(__stack_chk_guard, cpu) = idle->stack_canary; 58 - #endif 59 61 } 60 62 61 63 #else /* STACKPROTECTOR */
-6
arch/x86/kernel/asm-offsets_64.c
··· 54 54 BLANK(); 55 55 #undef ENTRY 56 56 57 - BLANK(); 58 - 59 - #ifdef CONFIG_STACKPROTECTOR 60 - OFFSET(FIXED_stack_canary, fixed_percpu_data, stack_canary); 61 - BLANK(); 62 - #endif 63 57 return 0; 64 58 }
+1 -4
arch/x86/kernel/cpu/common.c
··· 2089 2089 if (!cpu_feature_enabled(X86_FEATURE_FRED)) 2090 2090 idt_syscall_init(); 2091 2091 } 2092 - 2093 - #else /* CONFIG_X86_64 */ 2092 + #endif /* CONFIG_X86_64 */ 2094 2093 2095 2094 #ifdef CONFIG_STACKPROTECTOR 2096 2095 DEFINE_PER_CPU(unsigned long, __stack_chk_guard); ··· 2097 2098 EXPORT_PER_CPU_SYMBOL(__stack_chk_guard); 2098 2099 #endif 2099 2100 #endif 2100 - 2101 - #endif /* CONFIG_X86_64 */ 2102 2101 2103 2102 /* 2104 2103 * Clear all 6 debug registers:
+1 -2
arch/x86/kernel/head_64.S
··· 361 361 362 362 /* Set up %gs. 363 363 * 364 - * The base of %gs always points to fixed_percpu_data. If the 365 - * stack protector canary is enabled, it is located at %gs:40. 364 + * The base of %gs always points to fixed_percpu_data. 366 365 * Note that, on SMP, the boot cpu uses init data section until 367 366 * the per cpu areas are set up. 368 367 */
+1 -2
arch/x86/xen/xen-head.S
··· 33 33 34 34 /* Set up %gs. 35 35 * 36 - * The base of %gs always points to fixed_percpu_data. If the 37 - * stack protector canary is enabled, it is located at %gs:40. 36 + * The base of %gs always points to fixed_percpu_data. 38 37 * Note that, on SMP, the boot cpu uses init data section until 39 38 * the per cpu areas are set up. 40 39 */