Commit ec3e837d authored by Ilya Leoshkevich's avatar Ilya Leoshkevich Committed by Andrew Morton

kmsan: allow disabling KMSAN checks for the current task

Like for KASAN, it's useful to temporarily disable KMSAN checks around,
e.g., redzone accesses.  Introduce kmsan_disable_current() and
kmsan_enable_current(), which are similar to their KASAN counterparts.

Make them reentrant in order to handle memory allocations in interrupt
context.  Repurpose the allow_reporting field for this.

Link: https://lkml.kernel.org/r/20240621113706.315500-12-iii@linux.ibm.comSigned-off-by: default avatarIlya Leoshkevich <iii@linux.ibm.com>
Reviewed-by: default avatarAlexander Potapenko <glider@google.com>
Cc: Alexander Gordeev <agordeev@linux.ibm.com>
Cc: Christian Borntraeger <borntraeger@linux.ibm.com>
Cc: Christoph Lameter <cl@linux.com>
Cc: David Rientjes <rientjes@google.com>
Cc: Dmitry Vyukov <dvyukov@google.com>
Cc: Heiko Carstens <hca@linux.ibm.com>
Cc: Hyeonggon Yoo <42.hyeyoo@gmail.com>
Cc: Joonsoo Kim <iamjoonsoo.kim@lge.com>
Cc: <kasan-dev@googlegroups.com>
Cc: Marco Elver <elver@google.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Masami Hiramatsu (Google) <mhiramat@kernel.org>
Cc: Pekka Enberg <penberg@kernel.org>
Cc: Roman Gushchin <roman.gushchin@linux.dev>
Cc: Steven Rostedt (Google) <rostedt@goodmis.org>
Cc: Sven Schnelle <svens@linux.ibm.com>
Cc: Vasily Gorbik <gor@linux.ibm.com>
Cc: Vlastimil Babka <vbabka@suse.cz>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
parent f2d62702
...@@ -110,6 +110,13 @@ in the Makefile. Think of this as applying ``__no_sanitize_memory`` to every ...@@ -110,6 +110,13 @@ in the Makefile. Think of this as applying ``__no_sanitize_memory`` to every
function in the file or directory. Most users won't need KMSAN_SANITIZE, unless function in the file or directory. Most users won't need KMSAN_SANITIZE, unless
their code gets broken by KMSAN (e.g. runs at early boot time). their code gets broken by KMSAN (e.g. runs at early boot time).
KMSAN checks can also be temporarily disabled for the current task using
``kmsan_disable_current()`` and ``kmsan_enable_current()`` calls. Each
``kmsan_enable_current()`` call must be preceded by a
``kmsan_disable_current()`` call; these call pairs may be nested. One needs to
be careful with these calls, keeping the regions short and preferring other
ways to disable instrumentation, where possible.
Support Support
======= =======
...@@ -338,11 +345,11 @@ Per-task KMSAN state ...@@ -338,11 +345,11 @@ Per-task KMSAN state
~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~
Every task_struct has an associated KMSAN task state that holds the KMSAN Every task_struct has an associated KMSAN task state that holds the KMSAN
context (see above) and a per-task flag disallowing KMSAN reports:: context (see above) and a per-task counter disallowing KMSAN reports::
struct kmsan_context { struct kmsan_context {
... ...
bool allow_reporting; unsigned int depth;
struct kmsan_context_state cstate; struct kmsan_context_state cstate;
... ...
} }
......
...@@ -239,6 +239,22 @@ void kmsan_unpoison_entry_regs(const struct pt_regs *regs); ...@@ -239,6 +239,22 @@ void kmsan_unpoison_entry_regs(const struct pt_regs *regs);
*/ */
void *kmsan_get_metadata(void *addr, bool is_origin); void *kmsan_get_metadata(void *addr, bool is_origin);
/**
* kmsan_enable_current(): Enable KMSAN for the current task.
*
* Each kmsan_enable_current() current call must be preceded by a
* kmsan_disable_current() call. These call pairs may be nested.
*/
void kmsan_enable_current(void);
/**
* kmsan_disable_current(): Disable KMSAN for the current task.
*
* Each kmsan_disable_current() current call must be followed by a
* kmsan_enable_current() call. These call pairs may be nested.
*/
void kmsan_disable_current(void);
#else #else
static inline void kmsan_init_shadow(void) static inline void kmsan_init_shadow(void)
...@@ -338,6 +354,14 @@ static inline void kmsan_unpoison_entry_regs(const struct pt_regs *regs) ...@@ -338,6 +354,14 @@ static inline void kmsan_unpoison_entry_regs(const struct pt_regs *regs)
{ {
} }
static inline void kmsan_enable_current(void)
{
}
static inline void kmsan_disable_current(void)
{
}
#endif #endif
#endif /* _LINUX_KMSAN_H */ #endif /* _LINUX_KMSAN_H */
...@@ -31,7 +31,7 @@ struct kmsan_context_state { ...@@ -31,7 +31,7 @@ struct kmsan_context_state {
struct kmsan_ctx { struct kmsan_ctx {
struct kmsan_context_state cstate; struct kmsan_context_state cstate;
int kmsan_in_runtime; int kmsan_in_runtime;
bool allow_reporting; unsigned int depth;
}; };
#endif /* _LINUX_KMSAN_TYPES_H */ #endif /* _LINUX_KMSAN_TYPES_H */
...@@ -43,7 +43,6 @@ void kmsan_internal_task_create(struct task_struct *task) ...@@ -43,7 +43,6 @@ void kmsan_internal_task_create(struct task_struct *task)
struct thread_info *info = current_thread_info(); struct thread_info *info = current_thread_info();
__memset(ctx, 0, sizeof(*ctx)); __memset(ctx, 0, sizeof(*ctx));
ctx->allow_reporting = true;
kmsan_internal_unpoison_memory(info, sizeof(*info), false); kmsan_internal_unpoison_memory(info, sizeof(*info), false);
} }
......
...@@ -39,12 +39,10 @@ void kmsan_task_create(struct task_struct *task) ...@@ -39,12 +39,10 @@ void kmsan_task_create(struct task_struct *task)
void kmsan_task_exit(struct task_struct *task) void kmsan_task_exit(struct task_struct *task)
{ {
struct kmsan_ctx *ctx = &task->kmsan_ctx;
if (!kmsan_enabled || kmsan_in_runtime()) if (!kmsan_enabled || kmsan_in_runtime())
return; return;
ctx->allow_reporting = false; kmsan_disable_current();
} }
void kmsan_slab_alloc(struct kmem_cache *s, void *object, gfp_t flags) void kmsan_slab_alloc(struct kmem_cache *s, void *object, gfp_t flags)
...@@ -424,3 +422,17 @@ void kmsan_check_memory(const void *addr, size_t size) ...@@ -424,3 +422,17 @@ void kmsan_check_memory(const void *addr, size_t size)
REASON_ANY); REASON_ANY);
} }
EXPORT_SYMBOL(kmsan_check_memory); EXPORT_SYMBOL(kmsan_check_memory);
void kmsan_enable_current(void)
{
KMSAN_WARN_ON(current->kmsan_ctx.depth == 0);
current->kmsan_ctx.depth--;
}
EXPORT_SYMBOL(kmsan_enable_current);
void kmsan_disable_current(void)
{
current->kmsan_ctx.depth++;
KMSAN_WARN_ON(current->kmsan_ctx.depth == 0);
}
EXPORT_SYMBOL(kmsan_disable_current);
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
*/ */
#include <linux/console.h> #include <linux/console.h>
#include <linux/kmsan.h>
#include <linux/moduleparam.h> #include <linux/moduleparam.h>
#include <linux/stackdepot.h> #include <linux/stackdepot.h>
#include <linux/stacktrace.h> #include <linux/stacktrace.h>
...@@ -158,12 +159,12 @@ void kmsan_report(depot_stack_handle_t origin, void *address, int size, ...@@ -158,12 +159,12 @@ void kmsan_report(depot_stack_handle_t origin, void *address, int size,
if (!kmsan_enabled) if (!kmsan_enabled)
return; return;
if (!current->kmsan_ctx.allow_reporting) if (current->kmsan_ctx.depth)
return; return;
if (!origin) if (!origin)
return; return;
current->kmsan_ctx.allow_reporting = false; kmsan_disable_current();
ua_flags = user_access_save(); ua_flags = user_access_save();
raw_spin_lock(&kmsan_report_lock); raw_spin_lock(&kmsan_report_lock);
pr_err("=====================================================\n"); pr_err("=====================================================\n");
...@@ -216,5 +217,5 @@ void kmsan_report(depot_stack_handle_t origin, void *address, int size, ...@@ -216,5 +217,5 @@ void kmsan_report(depot_stack_handle_t origin, void *address, int size,
if (panic_on_kmsan) if (panic_on_kmsan)
panic("kmsan.panic set ...\n"); panic("kmsan.panic set ...\n");
user_access_restore(ua_flags); user_access_restore(ua_flags);
current->kmsan_ctx.allow_reporting = true; kmsan_enable_current();
} }
...@@ -1202,6 +1202,8 @@ static const char *uaccess_safe_builtin[] = { ...@@ -1202,6 +1202,8 @@ static const char *uaccess_safe_builtin[] = {
"__sanitizer_cov_trace_switch", "__sanitizer_cov_trace_switch",
/* KMSAN */ /* KMSAN */
"kmsan_copy_to_user", "kmsan_copy_to_user",
"kmsan_disable_current",
"kmsan_enable_current",
"kmsan_report", "kmsan_report",
"kmsan_unpoison_entry_regs", "kmsan_unpoison_entry_regs",
"kmsan_unpoison_memory", "kmsan_unpoison_memory",
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment