// 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> *
*/
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);
/* * 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)
{ unsignedlong 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.
*/ staticinlinevoid get_param0_metadata(u64 *shadow,
depot_stack_handle_t *origin)
{ struct kmsan_ctx *ctx = kmsan_get_context();
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;
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();
/* * 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; unsignedlong 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; unsignedlong entries[4]; unsignedlong 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;
/* * 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)
{
kmsan_report(origin, /*address*/ NULL, /*size*/ 0, /*off_first*/ 0, /*off_last*/ 0, /*user_addr*/ NULL,
REASON_ANY);
}
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);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.