[PATCH v5 07/16] x86/module: Deal with GOT based stack cookie load on Clang < 17

Brian Gerst posted 16 patches 2 weeks, 4 days ago
[PATCH v5 07/16] x86/module: Deal with GOT based stack cookie load on Clang < 17
Posted by Brian Gerst 2 weeks, 4 days ago
From: Ard Biesheuvel <ardb@kernel.org>

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.

Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
Signed-off-by: Brian Gerst <brgerst@gmail.com>
---
 arch/x86/include/asm/elf.h |  3 ++-
 arch/x86/kernel/module.c   | 15 +++++++++++++++
 2 files changed, 17 insertions(+), 1 deletion(-)

diff --git a/arch/x86/include/asm/elf.h b/arch/x86/include/asm/elf.h
index 1fb83d47711f..0d6ca771549d 100644
--- a/arch/x86/include/asm/elf.h
+++ b/arch/x86/include/asm/elf.h
@@ -55,7 +55,8 @@ typedef struct user_i387_struct elf_fpregset_t;
 #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_GOTPCRELX	41	   offset to GOT */
+#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 */
diff --git a/arch/x86/kernel/module.c b/arch/x86/kernel/module.c
index 837450b6e882..9929be7a76e7 100644
--- a/arch/x86/kernel/module.c
+++ b/arch/x86/kernel/module.c
@@ -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;
-- 
2.47.0
RE: [PATCH v5 07/16] x86/module: Deal with GOT based stack cookie load on Clang < 17
Posted by David Laight 2 weeks, 1 day ago
From: Brian Gerst
> Sent: 05 November 2024 15:58
> 
> From: Ard Biesheuvel <ardb@kernel.org>
> 
> 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.
> 
...
> +#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

Doesn't this depend on the compiler used to compile the module not that
used to compile this code?
(In principle external modules should be able to use a different compiler.)

So the CLANG tests should be replaced by a comment.

	David

-
Registered Address Lakeside, Bramley Road, Mount Farm, Milton Keynes, MK1 1PT, UK
Registration No: 1397386 (Wales)