x86/module: Deal with GOT based stack cookie load on Clang < 17
authorArd Biesheuvel <ardb@kernel.org>
Thu, 23 Jan 2025 19:07:38 +0000 (14:07 -0500)
committerIngo Molnar <mingo@kernel.org>
Tue, 18 Feb 2025 09:15:05 +0000 (10:15 +0100)
Clang versions before 17 will not honour -fdirect-access-external-data
for the load of the stack cookie emitted into each function's prologue
and epilogue.

This is not an issue for the core kernel, as the linker will relax these
loads into LEA instructions that take the address of __stack_chk_guard
directly. For modules, however, we need to work around this, by dealing
with R_X86_64_REX_GOTPCRELX relocations that refer to __stack_chk_guard.

In this case, given that this is a GOT load, the reference should not
refer to __stack_chk_guard directly, but to a memory location that holds
its address. So take the address of __stack_chk_guard into a static
variable, and fix up the relocations to refer to that.

[ mingo: Fix broken R_X86_64_GOTPCRELX definition. ]

Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
Signed-off-by: Brian Gerst <brgerst@gmail.com>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Link: https://lore.kernel.org/r/20250123190747.745588-7-brgerst@gmail.com
arch/x86/include/asm/elf.h
arch/x86/kernel/module.c

index 1fb83d47711f97da6f24d14f0bb3b1d9cab55240..128602612ecaa5a7f9a8869eb6990876e7491344 100644 (file)
@@ -54,8 +54,9 @@ typedef struct user_i387_struct elf_fpregset_t;
 #define R_X86_64_GLOB_DAT      6       /* Create GOT entry */
 #define R_X86_64_JUMP_SLOT     7       /* Create PLT entry */
 #define R_X86_64_RELATIVE      8       /* Adjust by program base */
-#define R_X86_64_GOTPCREL      9       /* 32 bit signed pc relative
-                                          offset to GOT */
+#define R_X86_64_GOTPCREL      9       /* 32 bit signed pc relative offset to GOT */
+#define R_X86_64_GOTPCRELX     41
+#define R_X86_64_REX_GOTPCRELX 42
 #define R_X86_64_32            10      /* Direct 32 bit zero extended */
 #define R_X86_64_32S           11      /* Direct 32 bit sign extended */
 #define R_X86_64_16            12      /* Direct 16 bit zero extended */
index 8984abd91c001fbcd64fa690d4a97dc3e341906d..a286f32c550365dabf6c69444345a50f9dea8617 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/jump_label.h>
 #include <linux/random.h>
 #include <linux/memory.h>
+#include <linux/stackprotector.h>
 
 #include <asm/text-patching.h>
 #include <asm/page.h>
@@ -130,6 +131,20 @@ static int __write_relocate_add(Elf64_Shdr *sechdrs,
                                goto overflow;
                        size = 4;
                        break;
+#if defined(CONFIG_STACKPROTECTOR) && \
+    defined(CONFIG_CC_IS_CLANG) && CONFIG_CLANG_VERSION < 170000
+               case R_X86_64_REX_GOTPCRELX: {
+                       static unsigned long __percpu *const addr = &__stack_chk_guard;
+
+                       if (sym->st_value != (u64)addr) {
+                               pr_err("%s: Unsupported GOTPCREL relocation\n", me->name);
+                               return -ENOEXEC;
+                       }
+
+                       val = (u64)&addr + rel[i].r_addend;
+                       fallthrough;
+               }
+#endif
                case R_X86_64_PC32:
                case R_X86_64_PLT32:
                        val -= (u64)loc;