mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 02:30:34 +02:00 
			
		
		
		
	entry, kasan, x86: Disallow overriding mem*() functions
KASAN cannot just hijack the mem*() functions, it needs to emit __asan_mem*() variants if it wants instrumentation (other sanitizers already do this). vmlinux.o: warning: objtool: sync_regs+0x24: call to memcpy() leaves .noinstr.text section vmlinux.o: warning: objtool: vc_switch_off_ist+0xbe: call to memcpy() leaves .noinstr.text section vmlinux.o: warning: objtool: fixup_bad_iret+0x36: call to memset() leaves .noinstr.text section vmlinux.o: warning: objtool: __sev_get_ghcb+0xa0: call to memcpy() leaves .noinstr.text section vmlinux.o: warning: objtool: __sev_put_ghcb+0x35: call to memcpy() leaves .noinstr.text section Remove the weak aliases to ensure nobody hijacks these functions and add them to the noinstr section. Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Signed-off-by: Ingo Molnar <mingo@kernel.org> Tested-by: Tony Lindgren <tony@atomide.com> Tested-by: Ulf Hansson <ulf.hansson@linaro.org> Acked-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Acked-by: Frederic Weisbecker <frederic@kernel.org> Link: https://lore.kernel.org/r/20230112195542.028523143@infradead.org
This commit is contained in:
		
							parent
							
								
									365bd03ff6
								
							
						
					
					
						commit
						69d4c0d321
					
				
					 6 changed files with 53 additions and 5 deletions
				
			
		| 
						 | 
				
			
			@ -8,7 +8,7 @@
 | 
			
		|||
#include <asm/alternative.h>
 | 
			
		||||
#include <asm/export.h>
 | 
			
		||||
 | 
			
		||||
.pushsection .noinstr.text, "ax"
 | 
			
		||||
.section .noinstr.text, "ax"
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * We build a jump to memcpy_orig by default which gets NOPped out on
 | 
			
		||||
| 
						 | 
				
			
			@ -43,7 +43,7 @@ SYM_TYPED_FUNC_START(__memcpy)
 | 
			
		|||
SYM_FUNC_END(__memcpy)
 | 
			
		||||
EXPORT_SYMBOL(__memcpy)
 | 
			
		||||
 | 
			
		||||
SYM_FUNC_ALIAS_WEAK(memcpy, __memcpy)
 | 
			
		||||
SYM_FUNC_ALIAS(memcpy, __memcpy)
 | 
			
		||||
EXPORT_SYMBOL(memcpy)
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
| 
						 | 
				
			
			@ -184,4 +184,3 @@ SYM_FUNC_START_LOCAL(memcpy_orig)
 | 
			
		|||
	RET
 | 
			
		||||
SYM_FUNC_END(memcpy_orig)
 | 
			
		||||
 | 
			
		||||
.popsection
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -13,6 +13,8 @@
 | 
			
		|||
 | 
			
		||||
#undef memmove
 | 
			
		||||
 | 
			
		||||
.section .noinstr.text, "ax"
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Implement memmove(). This can handle overlap between src and dst.
 | 
			
		||||
 *
 | 
			
		||||
| 
						 | 
				
			
			@ -213,5 +215,5 @@ SYM_FUNC_START(__memmove)
 | 
			
		|||
SYM_FUNC_END(__memmove)
 | 
			
		||||
EXPORT_SYMBOL(__memmove)
 | 
			
		||||
 | 
			
		||||
SYM_FUNC_ALIAS_WEAK(memmove, __memmove)
 | 
			
		||||
SYM_FUNC_ALIAS(memmove, __memmove)
 | 
			
		||||
EXPORT_SYMBOL(memmove)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -6,6 +6,8 @@
 | 
			
		|||
#include <asm/alternative.h>
 | 
			
		||||
#include <asm/export.h>
 | 
			
		||||
 | 
			
		||||
.section .noinstr.text, "ax"
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * ISO C memset - set a memory block to a byte value. This function uses fast
 | 
			
		||||
 * string to get better performance than the original function. The code is
 | 
			
		||||
| 
						 | 
				
			
			@ -43,7 +45,7 @@ SYM_FUNC_START(__memset)
 | 
			
		|||
SYM_FUNC_END(__memset)
 | 
			
		||||
EXPORT_SYMBOL(__memset)
 | 
			
		||||
 | 
			
		||||
SYM_FUNC_ALIAS_WEAK(memset, __memset)
 | 
			
		||||
SYM_FUNC_ALIAS(memset, __memset)
 | 
			
		||||
EXPORT_SYMBOL(memset)
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -618,6 +618,10 @@ void __asan_set_shadow_f3(const void *addr, size_t size);
 | 
			
		|||
void __asan_set_shadow_f5(const void *addr, size_t size);
 | 
			
		||||
void __asan_set_shadow_f8(const void *addr, size_t size);
 | 
			
		||||
 | 
			
		||||
void *__asan_memset(void *addr, int c, size_t len);
 | 
			
		||||
void *__asan_memmove(void *dest, const void *src, size_t len);
 | 
			
		||||
void *__asan_memcpy(void *dest, const void *src, size_t len);
 | 
			
		||||
 | 
			
		||||
void __hwasan_load1_noabort(unsigned long addr);
 | 
			
		||||
void __hwasan_store1_noabort(unsigned long addr);
 | 
			
		||||
void __hwasan_load2_noabort(unsigned long addr);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -38,6 +38,12 @@ bool __kasan_check_write(const volatile void *p, unsigned int size)
 | 
			
		|||
}
 | 
			
		||||
EXPORT_SYMBOL(__kasan_check_write);
 | 
			
		||||
 | 
			
		||||
#ifndef CONFIG_GENERIC_ENTRY
 | 
			
		||||
/*
 | 
			
		||||
 * CONFIG_GENERIC_ENTRY relies on compiler emitted mem*() calls to not be
 | 
			
		||||
 * instrumented. KASAN enabled toolchains should emit __asan_mem*() functions
 | 
			
		||||
 * for the sites they want to instrument.
 | 
			
		||||
 */
 | 
			
		||||
#undef memset
 | 
			
		||||
void *memset(void *addr, int c, size_t len)
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -68,6 +74,38 @@ void *memcpy(void *dest, const void *src, size_t len)
 | 
			
		|||
 | 
			
		||||
	return __memcpy(dest, src, len);
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
void *__asan_memset(void *addr, int c, size_t len)
 | 
			
		||||
{
 | 
			
		||||
	if (!kasan_check_range((unsigned long)addr, len, true, _RET_IP_))
 | 
			
		||||
		return NULL;
 | 
			
		||||
 | 
			
		||||
	return __memset(addr, c, len);
 | 
			
		||||
}
 | 
			
		||||
EXPORT_SYMBOL(__asan_memset);
 | 
			
		||||
 | 
			
		||||
#ifdef __HAVE_ARCH_MEMMOVE
 | 
			
		||||
void *__asan_memmove(void *dest, const void *src, size_t len)
 | 
			
		||||
{
 | 
			
		||||
	if (!kasan_check_range((unsigned long)src, len, false, _RET_IP_) ||
 | 
			
		||||
	    !kasan_check_range((unsigned long)dest, len, true, _RET_IP_))
 | 
			
		||||
		return NULL;
 | 
			
		||||
 | 
			
		||||
	return __memmove(dest, src, len);
 | 
			
		||||
}
 | 
			
		||||
EXPORT_SYMBOL(__asan_memmove);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
void *__asan_memcpy(void *dest, const void *src, size_t len)
 | 
			
		||||
{
 | 
			
		||||
	if (!kasan_check_range((unsigned long)src, len, false, _RET_IP_) ||
 | 
			
		||||
	    !kasan_check_range((unsigned long)dest, len, true, _RET_IP_))
 | 
			
		||||
		return NULL;
 | 
			
		||||
 | 
			
		||||
	return __memcpy(dest, src, len);
 | 
			
		||||
}
 | 
			
		||||
EXPORT_SYMBOL(__asan_memcpy);
 | 
			
		||||
 | 
			
		||||
void kasan_poison(const void *addr, size_t size, u8 value, bool init)
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1074,6 +1074,9 @@ static const char *uaccess_safe_builtin[] = {
 | 
			
		|||
	"__asan_store16_noabort",
 | 
			
		||||
	"__kasan_check_read",
 | 
			
		||||
	"__kasan_check_write",
 | 
			
		||||
	"__asan_memset",
 | 
			
		||||
	"__asan_memmove",
 | 
			
		||||
	"__asan_memcpy",
 | 
			
		||||
	/* KASAN in-line */
 | 
			
		||||
	"__asan_report_load_n_noabort",
 | 
			
		||||
	"__asan_report_load1_noabort",
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue