| From d4c7992dd690217654b268f930cebd08a21cb6c4 Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Mon, 24 Mar 2025 14:56:12 -0700 |
| Subject: objtool, lkdtm: Obfuscate the do_nothing() pointer |
| |
| From: Josh Poimboeuf <jpoimboe@kernel.org> |
| |
| [ Upstream commit 05026ea01e95ffdeb0e5ac8fb7fb1b551e3a8726 ] |
| |
| If execute_location()'s memcpy of do_nothing() gets inlined and unrolled |
| by the compiler, it copies one word at a time: |
| |
| mov 0x0(%rip),%rax R_X86_64_PC32 .text+0x1374 |
| mov %rax,0x38(%rbx) |
| mov 0x0(%rip),%rax R_X86_64_PC32 .text+0x136c |
| mov %rax,0x30(%rbx) |
| ... |
| |
| Those .text references point to the middle of the function, causing |
| objtool to complain about their lack of ENDBR. |
| |
| Prevent that by resolving the function pointer at runtime rather than |
| build time. This fixes the following warning: |
| |
| drivers/misc/lkdtm/lkdtm.o: warning: objtool: execute_location+0x23: relocation to !ENDBR: .text+0x1378 |
| |
| Reported-by: kernel test robot <lkp@intel.com> |
| Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org> |
| Signed-off-by: Ingo Molnar <mingo@kernel.org> |
| Reviewed-by: Kees Cook <kees@kernel.org> |
| Cc: Arnd Bergmann <arnd@arndb.de> |
| Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| Cc: Linus Torvalds <torvalds@linux-foundation.org> |
| Link: https://lore.kernel.org/r/30b9abffbddeb43c4f6320b1270fa9b4d74c54ed.1742852847.git.jpoimboe@kernel.org |
| Closes: https://lore.kernel.org/oe-kbuild-all/202503191453.uFfxQy5R-lkp@intel.com/ |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| drivers/misc/lkdtm/perms.c | 14 +++++++++++--- |
| 1 file changed, 11 insertions(+), 3 deletions(-) |
| |
| diff --git a/drivers/misc/lkdtm/perms.c b/drivers/misc/lkdtm/perms.c |
| index b93404d656509..e82d9543a0c5f 100644 |
| --- a/drivers/misc/lkdtm/perms.c |
| +++ b/drivers/misc/lkdtm/perms.c |
| @@ -28,6 +28,13 @@ static const unsigned long rodata = 0xAA55AA55; |
| /* This is marked __ro_after_init, so it should ultimately be .rodata. */ |
| static unsigned long ro_after_init __ro_after_init = 0x55AA5500; |
| |
| +/* |
| + * This is a pointer to do_nothing() which is initialized at runtime rather |
| + * than build time to avoid objtool IBT validation warnings caused by an |
| + * inlined unrolled memcpy() in execute_location(). |
| + */ |
| +static void __ro_after_init *do_nothing_ptr; |
| + |
| /* |
| * This just returns to the caller. It is designed to be copied into |
| * non-executable memory regions. |
| @@ -65,13 +72,12 @@ static noinline void execute_location(void *dst, bool write) |
| { |
| void (*func)(void); |
| func_desc_t fdesc; |
| - void *do_nothing_text = dereference_function_descriptor(do_nothing); |
| |
| - pr_info("attempting ok execution at %px\n", do_nothing_text); |
| + pr_info("attempting ok execution at %px\n", do_nothing_ptr); |
| do_nothing(); |
| |
| if (write == CODE_WRITE) { |
| - memcpy(dst, do_nothing_text, EXEC_SIZE); |
| + memcpy(dst, do_nothing_ptr, EXEC_SIZE); |
| flush_icache_range((unsigned long)dst, |
| (unsigned long)dst + EXEC_SIZE); |
| } |
| @@ -267,6 +273,8 @@ static void lkdtm_ACCESS_NULL(void) |
| |
| void __init lkdtm_perms_init(void) |
| { |
| + do_nothing_ptr = dereference_function_descriptor(do_nothing); |
| + |
| /* Make sure we can write to __ro_after_init values during __init */ |
| ro_after_init |= 0xAA; |
| } |
| -- |
| 2.39.5 |
| |