Skip to content

Commit 8b87743

Browse files
ardbiesheuvelSasha Levin
authored and
Sasha Levin
committed
x86/stackprotector: Work around strict Clang TLS symbol requirements
[ Upstream commit 577c134 ] GCC and Clang both implement stack protector support based on Thread Local Storage (TLS) variables, and this is used in the kernel to implement per-task stack cookies, by copying a task's stack cookie into a per-CPU variable every time it is scheduled in. Both now also implement -mstack-protector-guard-symbol=, which permits the TLS variable to be specified directly. This is useful because it will allow to move away from using a fixed offset of 40 bytes into the per-CPU area on x86_64, which requires a lot of special handling in the per-CPU code and the runtime relocation code. However, while GCC is rather lax in its implementation of this command line option, Clang actually requires that the provided symbol name refers to a TLS variable (i.e., one declared with __thread), although it also permits the variable to be undeclared entirely, in which case it will use an implicit declaration of the right type. The upshot of this is that Clang will emit the correct references to the stack cookie variable in most cases, e.g., 10d: 64 a1 00 00 00 00 mov %fs:0x0,%eax 10f: R_386_32 __stack_chk_guard However, if a non-TLS definition of the symbol in question is visible in the same compilation unit (which amounts to the whole of vmlinux if LTO is enabled), it will drop the per-CPU prefix and emit a load from a bogus address. Work around this by using a symbol name that never occurs in C code, and emit it as an alias in the linker script. Fixes: 3fb0fdb ("x86/stackprotector/32: Make the canary into a regular percpu variable") Signed-off-by: Ard Biesheuvel <[email protected]> Signed-off-by: Brian Gerst <[email protected]> Signed-off-by: Borislav Petkov (AMD) <[email protected]> Reviewed-by: Nathan Chancellor <[email protected]> Tested-by: Nathan Chancellor <[email protected]> Cc: [email protected] Link: ClangBuiltLinux/linux#1854 Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Sasha Levin <[email protected]>
1 parent 8eb7b29 commit 8b87743

File tree

5 files changed

+25
-1
lines changed

5 files changed

+25
-1
lines changed

arch/x86/Makefile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,8 @@ ifeq ($(CONFIG_X86_32),y)
9090

9191
ifeq ($(CONFIG_STACKPROTECTOR),y)
9292
ifeq ($(CONFIG_SMP),y)
93-
KBUILD_CFLAGS += -mstack-protector-guard-reg=fs -mstack-protector-guard-symbol=__stack_chk_guard
93+
KBUILD_CFLAGS += -mstack-protector-guard-reg=fs \
94+
-mstack-protector-guard-symbol=__ref_stack_chk_guard
9495
else
9596
KBUILD_CFLAGS += -mstack-protector-guard=global
9697
endif

arch/x86/entry/entry.S

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,3 +48,18 @@ EXPORT_SYMBOL_GPL(mds_verw_sel);
4848

4949
.popsection
5050

51+
#ifndef CONFIG_X86_64
52+
/*
53+
* Clang's implementation of TLS stack cookies requires the variable in
54+
* question to be a TLS variable. If the variable happens to be defined as an
55+
* ordinary variable with external linkage in the same compilation unit (which
56+
* amounts to the whole of vmlinux with LTO enabled), Clang will drop the
57+
* segment register prefix from the references, resulting in broken code. Work
58+
* around this by avoiding the symbol used in -mstack-protector-guard-symbol=
59+
* entirely in the C code, and use an alias emitted by the linker script
60+
* instead.
61+
*/
62+
#ifdef CONFIG_STACKPROTECTOR
63+
EXPORT_SYMBOL(__ref_stack_chk_guard);
64+
#endif
65+
#endif

arch/x86/include/asm/asm-prototypes.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,6 @@
1818
extern void cmpxchg8b_emu(void);
1919
#endif
2020

21+
#if defined(__GENKSYMS__) && defined(CONFIG_STACKPROTECTOR)
22+
extern unsigned long __ref_stack_chk_guard;
23+
#endif

arch/x86/kernel/cpu/common.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1974,8 +1974,10 @@ EXPORT_PER_CPU_SYMBOL(cpu_current_top_of_stack);
19741974

19751975
#ifdef CONFIG_STACKPROTECTOR
19761976
DEFINE_PER_CPU(unsigned long, __stack_chk_guard);
1977+
#ifndef CONFIG_SMP
19771978
EXPORT_PER_CPU_SYMBOL(__stack_chk_guard);
19781979
#endif
1980+
#endif
19791981

19801982
#endif /* CONFIG_X86_64 */
19811983

arch/x86/kernel/vmlinux.lds.S

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -490,6 +490,9 @@ SECTIONS
490490
ASSERT(SIZEOF(.rela.dyn) == 0, "Unexpected run-time relocations (.rela) detected!")
491491
}
492492

493+
/* needed for Clang - see arch/x86/entry/entry.S */
494+
PROVIDE(__ref_stack_chk_guard = __stack_chk_guard);
495+
493496
#ifdef CONFIG_X86_32
494497
/*
495498
* The ASSERT() sink to . is intentional, for binutils 2.14 compatibility:

0 commit comments

Comments
 (0)