335 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			335 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| // SPDX-License-Identifier: GPL-2.0
 | |
| /*
 | |
|  * KMSAN compiler API.
 | |
|  *
 | |
|  * This file implements __msan_XXX hooks that Clang inserts into the code
 | |
|  * compiled with -fsanitize=kernel-memory.
 | |
|  * See Documentation/dev-tools/kmsan.rst for more information on how KMSAN
 | |
|  * instrumentation works.
 | |
|  *
 | |
|  * Copyright (C) 2017-2022 Google LLC
 | |
|  * Author: Alexander Potapenko <glider@google.com>
 | |
|  *
 | |
|  */
 | |
| 
 | |
| #include "kmsan.h"
 | |
| #include <linux/gfp.h>
 | |
| #include <linux/kmsan.h>
 | |
| #include <linux/kmsan_string.h>
 | |
| #include <linux/mm.h>
 | |
| #include <linux/uaccess.h>
 | |
| 
 | |
| static inline bool is_bad_asm_addr(void *addr, uintptr_t size, bool is_store)
 | |
| {
 | |
| 	if (IS_ENABLED(CONFIG_ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE) &&
 | |
| 	    (u64)addr < TASK_SIZE)
 | |
| 		return true;
 | |
| 	if (!kmsan_get_metadata(addr, KMSAN_META_SHADOW))
 | |
| 		return true;
 | |
| 	return false;
 | |
| }
 | |
| 
 | |
| static inline struct shadow_origin_ptr
 | |
| get_shadow_origin_ptr(void *addr, u64 size, bool store)
 | |
| {
 | |
| 	unsigned long ua_flags = user_access_save();
 | |
| 	struct shadow_origin_ptr ret;
 | |
| 
 | |
| 	ret = kmsan_get_shadow_origin_ptr(addr, size, store);
 | |
| 	user_access_restore(ua_flags);
 | |
| 	return ret;
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * KMSAN instrumentation functions follow. They are not declared elsewhere in
 | |
|  * the kernel code, so they are preceded by prototypes, to silence
 | |
|  * -Wmissing-prototypes warnings.
 | |
|  */
 | |
| 
 | |
| /* Get shadow and origin pointers for a memory load with non-standard size. */
 | |
| struct shadow_origin_ptr __msan_metadata_ptr_for_load_n(void *addr,
 | |
| 							uintptr_t size);
 | |
| struct shadow_origin_ptr __msan_metadata_ptr_for_load_n(void *addr,
 | |
| 							uintptr_t size)
 | |
| {
 | |
| 	return get_shadow_origin_ptr(addr, size, /*store*/ false);
 | |
| }
 | |
| EXPORT_SYMBOL(__msan_metadata_ptr_for_load_n);
 | |
| 
 | |
| /* Get shadow and origin pointers for a memory store with non-standard size. */
 | |
| struct shadow_origin_ptr __msan_metadata_ptr_for_store_n(void *addr,
 | |
| 							 uintptr_t size);
 | |
| struct shadow_origin_ptr __msan_metadata_ptr_for_store_n(void *addr,
 | |
| 							 uintptr_t size)
 | |
| {
 | |
| 	return get_shadow_origin_ptr(addr, size, /*store*/ true);
 | |
| }
 | |
| EXPORT_SYMBOL(__msan_metadata_ptr_for_store_n);
 | |
| 
 | |
| /*
 | |
|  * Declare functions that obtain shadow/origin pointers for loads and stores
 | |
|  * with fixed size.
 | |
|  */
 | |
| #define DECLARE_METADATA_PTR_GETTER(size)                                  \
 | |
| 	struct shadow_origin_ptr __msan_metadata_ptr_for_load_##size(      \
 | |
| 		void *addr);                                               \
 | |
| 	struct shadow_origin_ptr __msan_metadata_ptr_for_load_##size(      \
 | |
| 		void *addr)                                                \
 | |
| 	{                                                                  \
 | |
| 		return get_shadow_origin_ptr(addr, size, /*store*/ false); \
 | |
| 	}                                                                  \
 | |
| 	EXPORT_SYMBOL(__msan_metadata_ptr_for_load_##size);                \
 | |
| 	struct shadow_origin_ptr __msan_metadata_ptr_for_store_##size(     \
 | |
| 		void *addr);                                               \
 | |
| 	struct shadow_origin_ptr __msan_metadata_ptr_for_store_##size(     \
 | |
| 		void *addr)                                                \
 | |
| 	{                                                                  \
 | |
| 		return get_shadow_origin_ptr(addr, size, /*store*/ true);  \
 | |
| 	}                                                                  \
 | |
| 	EXPORT_SYMBOL(__msan_metadata_ptr_for_store_##size)
 | |
| 
 | |
| DECLARE_METADATA_PTR_GETTER(1);
 | |
| DECLARE_METADATA_PTR_GETTER(2);
 | |
| DECLARE_METADATA_PTR_GETTER(4);
 | |
| DECLARE_METADATA_PTR_GETTER(8);
 | |
| 
 | |
| /*
 | |
|  * Handle a memory store performed by inline assembly. KMSAN conservatively
 | |
|  * attempts to unpoison the outputs of asm() directives to prevent false
 | |
|  * positives caused by missed stores.
 | |
|  *
 | |
|  * __msan_instrument_asm_store() may be called for inline assembly code when
 | |
|  * entering or leaving IRQ. We omit the check for kmsan_in_runtime() to ensure
 | |
|  * the memory written to in these cases is also marked as initialized.
 | |
|  */
 | |
| void __msan_instrument_asm_store(void *addr, uintptr_t size);
 | |
| void __msan_instrument_asm_store(void *addr, uintptr_t size)
 | |
| {
 | |
| 	unsigned long ua_flags;
 | |
| 
 | |
| 	if (!kmsan_enabled)
 | |
| 		return;
 | |
| 
 | |
| 	ua_flags = user_access_save();
 | |
| 	/*
 | |
| 	 * Most of the accesses are below 32 bytes. The exceptions so far are
 | |
| 	 * clwb() (64 bytes), FPU state (512 bytes) and chsc() (4096 bytes).
 | |
| 	 */
 | |
| 	if (size > 4096) {
 | |
| 		WARN_ONCE(1, "assembly store size too big: %ld\n", size);
 | |
| 		size = 8;
 | |
| 	}
 | |
| 	if (is_bad_asm_addr(addr, size, /*is_store*/ true)) {
 | |
| 		user_access_restore(ua_flags);
 | |
| 		return;
 | |
| 	}
 | |
| 	/* Unpoisoning the memory on best effort. */
 | |
| 	kmsan_internal_unpoison_memory(addr, size, /*checked*/ false);
 | |
| 	user_access_restore(ua_flags);
 | |
| }
 | |
| EXPORT_SYMBOL(__msan_instrument_asm_store);
 | |
| 
 | |
| /*
 | |
|  * KMSAN instrumentation pass replaces LLVM memcpy, memmove and memset
 | |
|  * intrinsics with calls to respective __msan_ functions. We use
 | |
|  * get_param0_metadata() and set_retval_metadata() to store the shadow/origin
 | |
|  * values for the destination argument of these functions and use them for the
 | |
|  * functions' return values.
 | |
|  */
 | |
| static inline void get_param0_metadata(u64 *shadow,
 | |
| 				       depot_stack_handle_t *origin)
 | |
| {
 | |
| 	struct kmsan_ctx *ctx = kmsan_get_context();
 | |
| 
 | |
| 	*shadow = *(u64 *)(ctx->cstate.param_tls);
 | |
| 	*origin = ctx->cstate.param_origin_tls[0];
 | |
| }
 | |
| 
 | |
| static inline void set_retval_metadata(u64 shadow, depot_stack_handle_t origin)
 | |
| {
 | |
| 	struct kmsan_ctx *ctx = kmsan_get_context();
 | |
| 
 | |
| 	*(u64 *)(ctx->cstate.retval_tls) = shadow;
 | |
| 	ctx->cstate.retval_origin_tls = origin;
 | |
| }
 | |
| 
 | |
| /* Handle llvm.memmove intrinsic. */
 | |
| void *__msan_memmove(void *dst, const void *src, uintptr_t n);
 | |
| void *__msan_memmove(void *dst, const void *src, uintptr_t n)
 | |
| {
 | |
| 	depot_stack_handle_t origin;
 | |
| 	void *result;
 | |
| 	u64 shadow;
 | |
| 
 | |
| 	get_param0_metadata(&shadow, &origin);
 | |
| 	result = __memmove(dst, src, n);
 | |
| 	if (!n)
 | |
| 		/* Some people call memmove() with zero length. */
 | |
| 		return result;
 | |
| 	if (!kmsan_enabled || kmsan_in_runtime())
 | |
| 		return result;
 | |
| 
 | |
| 	kmsan_enter_runtime();
 | |
| 	kmsan_internal_memmove_metadata(dst, (void *)src, n);
 | |
| 	kmsan_leave_runtime();
 | |
| 
 | |
| 	set_retval_metadata(shadow, origin);
 | |
| 	return result;
 | |
| }
 | |
| EXPORT_SYMBOL(__msan_memmove);
 | |
| 
 | |
| /* Handle llvm.memcpy intrinsic. */
 | |
| void *__msan_memcpy(void *dst, const void *src, uintptr_t n);
 | |
| void *__msan_memcpy(void *dst, const void *src, uintptr_t n)
 | |
| {
 | |
| 	depot_stack_handle_t origin;
 | |
| 	void *result;
 | |
| 	u64 shadow;
 | |
| 
 | |
| 	get_param0_metadata(&shadow, &origin);
 | |
| 	result = __memcpy(dst, src, n);
 | |
| 	if (!n)
 | |
| 		/* Some people call memcpy() with zero length. */
 | |
| 		return result;
 | |
| 
 | |
| 	if (!kmsan_enabled || kmsan_in_runtime())
 | |
| 		return result;
 | |
| 
 | |
| 	kmsan_enter_runtime();
 | |
| 	/* Using memmove instead of memcpy doesn't affect correctness. */
 | |
| 	kmsan_internal_memmove_metadata(dst, (void *)src, n);
 | |
| 	kmsan_leave_runtime();
 | |
| 
 | |
| 	set_retval_metadata(shadow, origin);
 | |
| 	return result;
 | |
| }
 | |
| EXPORT_SYMBOL(__msan_memcpy);
 | |
| 
 | |
| /* Handle llvm.memset intrinsic. */
 | |
| void *__msan_memset(void *dst, int c, uintptr_t n);
 | |
| void *__msan_memset(void *dst, int c, uintptr_t n)
 | |
| {
 | |
| 	depot_stack_handle_t origin;
 | |
| 	void *result;
 | |
| 	u64 shadow;
 | |
| 
 | |
| 	get_param0_metadata(&shadow, &origin);
 | |
| 	result = __memset(dst, c, n);
 | |
| 	if (!kmsan_enabled || kmsan_in_runtime())
 | |
| 		return result;
 | |
| 
 | |
| 	kmsan_enter_runtime();
 | |
| 	/*
 | |
| 	 * Clang doesn't pass parameter metadata here, so it is impossible to
 | |
| 	 * use shadow of @c to set up the shadow for @dst.
 | |
| 	 */
 | |
| 	kmsan_internal_unpoison_memory(dst, n, /*checked*/ false);
 | |
| 	kmsan_leave_runtime();
 | |
| 
 | |
| 	set_retval_metadata(shadow, origin);
 | |
| 	return result;
 | |
| }
 | |
| EXPORT_SYMBOL(__msan_memset);
 | |
| 
 | |
| /*
 | |
|  * Create a new origin from an old one. This is done when storing an
 | |
|  * uninitialized value to memory. When reporting an error, KMSAN unrolls and
 | |
|  * prints the whole chain of stores that preceded the use of this value.
 | |
|  */
 | |
| depot_stack_handle_t __msan_chain_origin(depot_stack_handle_t origin);
 | |
| depot_stack_handle_t __msan_chain_origin(depot_stack_handle_t origin)
 | |
| {
 | |
| 	depot_stack_handle_t ret = 0;
 | |
| 	unsigned long ua_flags;
 | |
| 
 | |
| 	if (!kmsan_enabled || kmsan_in_runtime())
 | |
| 		return ret;
 | |
| 
 | |
| 	ua_flags = user_access_save();
 | |
| 
 | |
| 	/* Creating new origins may allocate memory. */
 | |
| 	kmsan_enter_runtime();
 | |
| 	ret = kmsan_internal_chain_origin(origin);
 | |
| 	kmsan_leave_runtime();
 | |
| 	user_access_restore(ua_flags);
 | |
| 	return ret;
 | |
| }
 | |
| EXPORT_SYMBOL(__msan_chain_origin);
 | |
| 
 | |
| /* Poison a local variable when entering a function. */
 | |
| void __msan_poison_alloca(void *address, uintptr_t size, char *descr);
 | |
| void __msan_poison_alloca(void *address, uintptr_t size, char *descr)
 | |
| {
 | |
| 	depot_stack_handle_t handle;
 | |
| 	unsigned long entries[4];
 | |
| 	unsigned long ua_flags;
 | |
| 
 | |
| 	if (!kmsan_enabled || kmsan_in_runtime())
 | |
| 		return;
 | |
| 
 | |
| 	ua_flags = user_access_save();
 | |
| 	entries[0] = KMSAN_ALLOCA_MAGIC_ORIGIN;
 | |
| 	entries[1] = (u64)descr;
 | |
| 	entries[2] = (u64)__builtin_return_address(0);
 | |
| 	/*
 | |
| 	 * With frame pointers enabled, it is possible to quickly fetch the
 | |
| 	 * second frame of the caller stack without calling the unwinder.
 | |
| 	 * Without them, simply do not bother.
 | |
| 	 */
 | |
| 	if (IS_ENABLED(CONFIG_UNWINDER_FRAME_POINTER))
 | |
| 		entries[3] = (u64)__builtin_return_address(1);
 | |
| 	else
 | |
| 		entries[3] = 0;
 | |
| 
 | |
| 	/* stack_depot_save() may allocate memory. */
 | |
| 	kmsan_enter_runtime();
 | |
| 	handle = stack_depot_save(entries, ARRAY_SIZE(entries), __GFP_HIGH);
 | |
| 	kmsan_leave_runtime();
 | |
| 
 | |
| 	kmsan_internal_set_shadow_origin(address, size, -1, handle,
 | |
| 					 /*checked*/ true);
 | |
| 	user_access_restore(ua_flags);
 | |
| }
 | |
| EXPORT_SYMBOL(__msan_poison_alloca);
 | |
| 
 | |
| /* Unpoison a local variable. */
 | |
| void __msan_unpoison_alloca(void *address, uintptr_t size);
 | |
| void __msan_unpoison_alloca(void *address, uintptr_t size)
 | |
| {
 | |
| 	if (!kmsan_enabled || kmsan_in_runtime())
 | |
| 		return;
 | |
| 
 | |
| 	kmsan_enter_runtime();
 | |
| 	kmsan_internal_unpoison_memory(address, size, /*checked*/ true);
 | |
| 	kmsan_leave_runtime();
 | |
| }
 | |
| EXPORT_SYMBOL(__msan_unpoison_alloca);
 | |
| 
 | |
| /*
 | |
|  * Report that an uninitialized value with the given origin was used in a way
 | |
|  * that constituted undefined behavior.
 | |
|  */
 | |
| void __msan_warning(u32 origin);
 | |
| void __msan_warning(u32 origin)
 | |
| {
 | |
| 	if (!kmsan_enabled || kmsan_in_runtime())
 | |
| 		return;
 | |
| 	kmsan_enter_runtime();
 | |
| 	kmsan_report(origin, /*address*/ NULL, /*size*/ 0,
 | |
| 		     /*off_first*/ 0, /*off_last*/ 0, /*user_addr*/ NULL,
 | |
| 		     REASON_ANY);
 | |
| 	kmsan_leave_runtime();
 | |
| }
 | |
| EXPORT_SYMBOL(__msan_warning);
 | |
| 
 | |
| /*
 | |
|  * At the beginning of an instrumented function, obtain the pointer to
 | |
|  * `struct kmsan_context_state` holding the metadata for function parameters.
 | |
|  */
 | |
| struct kmsan_context_state *__msan_get_context_state(void);
 | |
| struct kmsan_context_state *__msan_get_context_state(void)
 | |
| {
 | |
| 	return &kmsan_get_context()->cstate;
 | |
| }
 | |
| EXPORT_SYMBOL(__msan_get_context_state);
 |