| // 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); |