mirror of
https://github.com/torvalds/linux.git
synced 2026-11-07 06:17:02 +01:00
powerpc/kasan: fix r2 corruption in mem*() on GENERIC_ENTRY with old compilers
commitbee25f97ad("powerpc: Enable GENERIC_ENTRY feature") introduced a bug that, when CONFIG_CC_HAS_KASAN_MEMINTRINSIC_PREFIX is not set, expand to two consecutive ELFv2 global entry points for the same function body: _GLOBAL_TOC_KASAN(memcpy) expands to: _GLOBAL_TOC(memcpy); _GLOBAL_TOC(__memcpy) On powerpc64le this produces: memcpy: addis r2,r12,(.TOC.-0b)@ha <- global entry, sets up r2 addi r2,r2,(.TOC.-0b)@l .localentry memcpy,.-memcpy <- local entry at memcpy+8 __memcpy: addis r2,r12,(.TOC.-0b)@ha <- memcpy+8: __memcpy global entry addi r2,r2,(.TOC.-0b)@l .localentry __memcpy,.-__memcpy The assembler sets memcpy's st_other field so its local entry offset is 8 bytes past the global entry point. The linker resolves same-TOC calls to the local entry, so every same-TOC caller of memcpy() lands at memcpy+8 — which is the beginning of the __memcpy global-entry TOC prologue. That prologue uses r12 as the base to recompute r2, but r12 holds whatever the caller left in it (not the address of memcpy+8). The result is r2 pointing at garbage on return. Same-TOC callers do not reload r2 after the call, so the first TOC-relative access after returning from memcpy() or memmove() crashes or silently corrupts data. With GENERIC_ENTRY selected, mm/kasan/shadow.c no longer provides its own memcpy()/memmove()/memset() wrappers, so on a toolchain without -mllvm -asan-kernel-mem-intrinsic-prefix=1 (e.g. GCC 9) every instrumented file resolves mem*() directly to the assembly symbols and hits this corrupt-r2 path. This manifests as an early boot hang unique to powerpc with GCC 9 and CONFIG_KASAN=y. Fix this by removing the dual-entry macros entirely. The assembly files in mem_64.S, memcpy_64.S and copy_32.S now use plain _GLOBAL()/_GLOBAL_TOC() for memset/memcpy/memmove, emitting a single correct ELFv2 entry point. The __mem* aliases required by mm/kasan (used in mm/kasan/shadow.c and mm/kasan/generic.c as raw backends to bypass KASAN checking) are provided entirely through the #define redirections in asm/string.h, which already handles both the CC_HAS_KASAN_MEMINTRINSIC_PREFIX and non-prefix cases in C. As a consequence the _GLOBAL_KASAN(), _GLOBAL_TOC_KASAN() and EXPORT_SYMBOL_KASAN() macros have no remaining users and are removed from asm/kasan.h. The has_renamed_memintrinsics() branch in prom_init_check.sh, which conditionally whitelisted __memcpy/__memset when CONFIG_CC_HAS_KASAN_MEMINTRINSIC_PREFIX was absent, is dead code after this change and is removed; the whitelist now unconditionally lists memcpy and memset. Fixes:bee25f97ad("powerpc: Enable GENERIC_ENTRY feature") Reported-by: Venkat Rao Bagalkote <venkat88@linux.ibm.com> Closes: https://lore.kernel.org/all/96dae110-f79b-4e54-8a9b-514369019b5d@linux.ibm.com Tested-by: Venkat Rao Bagalkote <venkat88@linux.ibm.com> Signed-off-by: Mukesh Kumar Chaurasiya (IBM) <mkchauras@gmail.com> [Maddy: Fixed commit message to avoid checkpatch error] Signed-off-by: Madhavan Srinivasan <maddy@linux.ibm.com> Link: https://patch.msgid.link/20261003094006.3404731-1-mkchauras@gmail.com
This commit is contained in:
parent
8fa763bc3e
commit
de5a7fedf5
|
|
@ -2,21 +2,6 @@
|
|||
#ifndef __ASM_KASAN_H
|
||||
#define __ASM_KASAN_H
|
||||
|
||||
#if defined(CONFIG_KASAN) && !defined(CONFIG_CC_HAS_KASAN_MEMINTRINSIC_PREFIX)
|
||||
#define _GLOBAL_KASAN(fn) \
|
||||
_GLOBAL(fn); \
|
||||
_GLOBAL(__##fn)
|
||||
#define _GLOBAL_TOC_KASAN(fn) \
|
||||
_GLOBAL_TOC(fn); \
|
||||
_GLOBAL_TOC(__##fn)
|
||||
#define EXPORT_SYMBOL_KASAN(fn) \
|
||||
EXPORT_SYMBOL(__##fn)
|
||||
#else /* CONFIG_KASAN && !CONFIG_CC_HAS_KASAN_MEMINTRINSIC_PREFIX */
|
||||
#define _GLOBAL_KASAN(fn) _GLOBAL(fn)
|
||||
#define _GLOBAL_TOC_KASAN(fn) _GLOBAL_TOC(fn)
|
||||
#define EXPORT_SYMBOL_KASAN(fn)
|
||||
#endif /* CONFIG_KASAN && !CONFIG_CC_HAS_KASAN_MEMINTRINSIC_PREFIX */
|
||||
|
||||
#ifndef __ASSEMBLER__
|
||||
|
||||
#include <asm/page.h>
|
||||
|
|
|
|||
|
|
@ -29,29 +29,10 @@ extern void * memchr(const void *,int,__kernel_size_t);
|
|||
void memcpy_flushcache(void *dest, const void *src, size_t size);
|
||||
|
||||
#ifdef CONFIG_KASAN
|
||||
/* __mem variants are used by KASAN to implement instrumented meminstrinsics. */
|
||||
#ifdef CONFIG_CC_HAS_KASAN_MEMINTRINSIC_PREFIX
|
||||
/* Used by mm/kasan as raw backends to bypass KASAN checking. */
|
||||
#define __memset memset
|
||||
#define __memcpy memcpy
|
||||
#define __memmove memmove
|
||||
#else /* CONFIG_CC_HAS_KASAN_MEMINTRINSIC_PREFIX */
|
||||
void *__memset(void *s, int c, __kernel_size_t count);
|
||||
void *__memcpy(void *to, const void *from, __kernel_size_t n);
|
||||
void *__memmove(void *to, const void *from, __kernel_size_t n);
|
||||
#ifndef __SANITIZE_ADDRESS__
|
||||
/*
|
||||
* For files that are not instrumented (e.g. mm/slub.c) we
|
||||
* should use not instrumented version of mem* functions.
|
||||
*/
|
||||
#define memcpy(dst, src, len) __memcpy(dst, src, len)
|
||||
#define memmove(dst, src, len) __memmove(dst, src, len)
|
||||
#define memset(s, c, n) __memset(s, c, n)
|
||||
|
||||
#ifndef __NO_FORTIFY
|
||||
#define __NO_FORTIFY /* FORTIFY_SOURCE uses __builtin_memcpy, etc. */
|
||||
#endif
|
||||
#endif /* !__SANITIZE_ADDRESS__ */
|
||||
#endif /* CONFIG_CC_HAS_KASAN_MEMINTRINSIC_PREFIX */
|
||||
#endif /* CONFIG_KASAN */
|
||||
|
||||
#ifdef CONFIG_PPC64
|
||||
|
|
|
|||
|
|
@ -35,12 +35,7 @@ void __init set_cur_cpu_spec(struct cpu_spec *s)
|
|||
struct cpu_spec *t = &the_cpu_spec;
|
||||
|
||||
t = PTRRELOC(t);
|
||||
/*
|
||||
* use memcpy() instead of *t = *s so that GCC replaces it
|
||||
* by __memcpy() when KASAN is active
|
||||
*/
|
||||
memcpy(t, s, sizeof(*t));
|
||||
|
||||
*t = *s;
|
||||
*PTRRELOC(&cur_cpu_spec) = &the_cpu_spec;
|
||||
}
|
||||
|
||||
|
|
@ -53,11 +48,8 @@ static struct cpu_spec * __init setup_cpu_spec(unsigned long offset,
|
|||
t = PTRRELOC(t);
|
||||
old = *t;
|
||||
|
||||
/*
|
||||
* Copy everything, then do fixups. Use memcpy() instead of *t = *s
|
||||
* so that GCC replaces it by __memcpy() when KASAN is active
|
||||
*/
|
||||
memcpy(t, s, sizeof(*t));
|
||||
/* Copy everything, then do fixups. */
|
||||
*t = *s;
|
||||
|
||||
/*
|
||||
* If we are overriding a previous value derived from the real
|
||||
|
|
|
|||
|
|
@ -1362,14 +1362,8 @@ static void __init prom_check_platform_support(void)
|
|||
int prop_len = prom_getproplen(prom.chosen,
|
||||
"ibm,arch-vec-5-platform-support");
|
||||
|
||||
/*
|
||||
* First copy the architecture vec template
|
||||
*
|
||||
* use memcpy() instead of *vec = *vec_template so that GCC replaces it
|
||||
* by __memcpy() when KASAN is active
|
||||
*/
|
||||
memcpy(&ibm_architecture_vec, &ibm_architecture_vec_template,
|
||||
sizeof(ibm_architecture_vec));
|
||||
/* First copy the architecture vec template */
|
||||
ibm_architecture_vec = ibm_architecture_vec_template;
|
||||
|
||||
prom_strscpy_pad(ibm_architecture_vec.vec7.os_id, linux_banner, 256);
|
||||
|
||||
|
|
|
|||
|
|
@ -13,21 +13,8 @@
|
|||
# If you really need to reference something from prom_init.o add
|
||||
# it to the list below:
|
||||
|
||||
has_renamed_memintrinsics()
|
||||
{
|
||||
grep -q "^CONFIG_KASAN=y$" "${KCONFIG_CONFIG}" && \
|
||||
! grep -q "^CONFIG_CC_HAS_KASAN_MEMINTRINSIC_PREFIX=y" "${KCONFIG_CONFIG}"
|
||||
}
|
||||
|
||||
if has_renamed_memintrinsics
|
||||
then
|
||||
MEM_FUNCS="__memcpy __memset"
|
||||
else
|
||||
MEM_FUNCS="memcpy memset"
|
||||
fi
|
||||
|
||||
WHITELIST="add_reloc_offset __bss_start __bss_stop copy_and_flush
|
||||
_end enter_prom $MEM_FUNCS reloc_offset __secondary_hold
|
||||
_end enter_prom memcpy memset reloc_offset __secondary_hold
|
||||
__secondary_hold_acknowledge __secondary_hold_spinloop __start
|
||||
logo_linux_clut224 btext_prepare_BAT
|
||||
reloc_got2 kernstart_addr memstart_addr linux_banner _stext
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@
|
|||
#include <asm/errno.h>
|
||||
#include <asm/ppc_asm.h>
|
||||
#include <asm/code-patching-asm.h>
|
||||
#include <asm/kasan.h>
|
||||
|
||||
#define COPY_16_BYTES \
|
||||
lwz r7,4(r4); \
|
||||
|
|
@ -87,7 +86,7 @@ EXPORT_SYMBOL(memset16)
|
|||
* We therefore skip the optimised bloc that uses dcbz. This jump is
|
||||
* replaced by a nop once cache is active. This is done in machine_init()
|
||||
*/
|
||||
_GLOBAL_KASAN(memset)
|
||||
_GLOBAL(memset)
|
||||
cmplwi 0,r5,4
|
||||
blt 7f
|
||||
|
||||
|
|
@ -147,7 +146,6 @@ _GLOBAL_KASAN(memset)
|
|||
bdnz 9b
|
||||
blr
|
||||
EXPORT_SYMBOL(memset)
|
||||
EXPORT_SYMBOL_KASAN(memset)
|
||||
|
||||
/*
|
||||
* This version uses dcbz on the complete cache lines in the
|
||||
|
|
@ -160,12 +158,12 @@ EXPORT_SYMBOL_KASAN(memset)
|
|||
* We therefore jump to generic_memcpy which doesn't use dcbz. This jump is
|
||||
* replaced by a nop once cache is active. This is done in machine_init()
|
||||
*/
|
||||
_GLOBAL_KASAN(memmove)
|
||||
_GLOBAL(memmove)
|
||||
cmplw 0,r3,r4
|
||||
bgt backwards_memcpy
|
||||
/* fall through */
|
||||
|
||||
_GLOBAL_KASAN(memcpy)
|
||||
_GLOBAL(memcpy)
|
||||
1: b generic_memcpy
|
||||
patch_site 1b, patch__memcpy_nocache
|
||||
|
||||
|
|
@ -241,8 +239,6 @@ _GLOBAL_KASAN(memcpy)
|
|||
65: blr
|
||||
EXPORT_SYMBOL(memcpy)
|
||||
EXPORT_SYMBOL(memmove)
|
||||
EXPORT_SYMBOL_KASAN(memcpy)
|
||||
EXPORT_SYMBOL_KASAN(memmove)
|
||||
|
||||
generic_memcpy:
|
||||
srwi. r7,r5,3
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@
|
|||
#include <asm/processor.h>
|
||||
#include <asm/errno.h>
|
||||
#include <asm/ppc_asm.h>
|
||||
#include <asm/kasan.h>
|
||||
|
||||
#ifndef CONFIG_KASAN
|
||||
_GLOBAL(__memset16)
|
||||
|
|
@ -29,7 +28,7 @@ EXPORT_SYMBOL(__memset32)
|
|||
EXPORT_SYMBOL(__memset64)
|
||||
#endif
|
||||
|
||||
_GLOBAL_KASAN(memset)
|
||||
_GLOBAL(memset)
|
||||
neg r0,r3
|
||||
rlwimi r4,r4,8,16,23
|
||||
andi. r0,r0,7 /* # bytes to be 8-byte aligned */
|
||||
|
|
@ -95,9 +94,8 @@ _GLOBAL_KASAN(memset)
|
|||
stb r4,0(r6)
|
||||
blr
|
||||
EXPORT_SYMBOL(memset)
|
||||
EXPORT_SYMBOL_KASAN(memset)
|
||||
|
||||
_GLOBAL_TOC_KASAN(memmove)
|
||||
_GLOBAL_TOC(memmove)
|
||||
cmplw 0,r3,r4
|
||||
bgt backwards_memcpy
|
||||
b memcpy
|
||||
|
|
@ -139,4 +137,3 @@ _GLOBAL(backwards_memcpy)
|
|||
mtctr r7
|
||||
b 1b
|
||||
EXPORT_SYMBOL(memmove)
|
||||
EXPORT_SYMBOL_KASAN(memmove)
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@
|
|||
#include <asm/ppc_asm.h>
|
||||
#include <asm/asm-compat.h>
|
||||
#include <asm/feature-fixups.h>
|
||||
#include <asm/kasan.h>
|
||||
|
||||
#ifndef SELFTEST_CASE
|
||||
/* For big-endian, 0 == most CPUs, 1 == POWER6, 2 == Cell */
|
||||
|
|
@ -15,7 +14,7 @@
|
|||
#endif
|
||||
|
||||
.align 7
|
||||
_GLOBAL_TOC_KASAN(memcpy)
|
||||
_GLOBAL_TOC(memcpy)
|
||||
BEGIN_FTR_SECTION
|
||||
#ifdef __LITTLE_ENDIAN__
|
||||
cmpdi cr7,r5,0
|
||||
|
|
@ -227,4 +226,3 @@ END_FTR_SECTION_IFCLR(CPU_FTR_UNALIGNED_LD_STD)
|
|||
blr
|
||||
#endif
|
||||
EXPORT_SYMBOL(memcpy)
|
||||
EXPORT_SYMBOL_KASAN(memcpy)
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user