Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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.com
Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com>
Reviewed-by: Alexander 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: Andrew Morton <akpm@linux-foundation.org>

authored by

Ilya Leoshkevich and committed by
Andrew Morton
ec3e837d f2d62702

+55 -10
+9 -2
Documentation/dev-tools/kmsan.rst
··· 110 110 function in the file or directory. Most users won't need KMSAN_SANITIZE, unless 111 111 their code gets broken by KMSAN (e.g. runs at early boot time). 112 112 113 + KMSAN checks can also be temporarily disabled for the current task using 114 + ``kmsan_disable_current()`` and ``kmsan_enable_current()`` calls. Each 115 + ``kmsan_enable_current()`` call must be preceded by a 116 + ``kmsan_disable_current()`` call; these call pairs may be nested. One needs to 117 + be careful with these calls, keeping the regions short and preferring other 118 + ways to disable instrumentation, where possible. 119 + 113 120 Support 114 121 ======= 115 122 ··· 345 338 ~~~~~~~~~~~~~~~~~~~~ 346 339 347 340 Every task_struct has an associated KMSAN task state that holds the KMSAN 348 - context (see above) and a per-task flag disallowing KMSAN reports:: 341 + context (see above) and a per-task counter disallowing KMSAN reports:: 349 342 350 343 struct kmsan_context { 351 344 ... 352 - bool allow_reporting; 345 + unsigned int depth; 353 346 struct kmsan_context_state cstate; 354 347 ... 355 348 }
+24
include/linux/kmsan.h
··· 239 239 */ 240 240 void *kmsan_get_metadata(void *addr, bool is_origin); 241 241 242 + /** 243 + * kmsan_enable_current(): Enable KMSAN for the current task. 244 + * 245 + * Each kmsan_enable_current() current call must be preceded by a 246 + * kmsan_disable_current() call. These call pairs may be nested. 247 + */ 248 + void kmsan_enable_current(void); 249 + 250 + /** 251 + * kmsan_disable_current(): Disable KMSAN for the current task. 252 + * 253 + * Each kmsan_disable_current() current call must be followed by a 254 + * kmsan_enable_current() call. These call pairs may be nested. 255 + */ 256 + void kmsan_disable_current(void); 257 + 242 258 #else 243 259 244 260 static inline void kmsan_init_shadow(void) ··· 351 335 } 352 336 353 337 static inline void kmsan_unpoison_entry_regs(const struct pt_regs *regs) 338 + { 339 + } 340 + 341 + static inline void kmsan_enable_current(void) 342 + { 343 + } 344 + 345 + static inline void kmsan_disable_current(void) 354 346 { 355 347 } 356 348
+1 -1
include/linux/kmsan_types.h
··· 31 31 struct kmsan_ctx { 32 32 struct kmsan_context_state cstate; 33 33 int kmsan_in_runtime; 34 - bool allow_reporting; 34 + unsigned int depth; 35 35 }; 36 36 37 37 #endif /* _LINUX_KMSAN_TYPES_H */
-1
mm/kmsan/core.c
··· 43 43 struct thread_info *info = current_thread_info(); 44 44 45 45 __memset(ctx, 0, sizeof(*ctx)); 46 - ctx->allow_reporting = true; 47 46 kmsan_internal_unpoison_memory(info, sizeof(*info), false); 48 47 } 49 48
+15 -3
mm/kmsan/hooks.c
··· 39 39 40 40 void kmsan_task_exit(struct task_struct *task) 41 41 { 42 - struct kmsan_ctx *ctx = &task->kmsan_ctx; 43 - 44 42 if (!kmsan_enabled || kmsan_in_runtime()) 45 43 return; 46 44 47 - ctx->allow_reporting = false; 45 + kmsan_disable_current(); 48 46 } 49 47 50 48 void kmsan_slab_alloc(struct kmem_cache *s, void *object, gfp_t flags) ··· 422 424 REASON_ANY); 423 425 } 424 426 EXPORT_SYMBOL(kmsan_check_memory); 427 + 428 + void kmsan_enable_current(void) 429 + { 430 + KMSAN_WARN_ON(current->kmsan_ctx.depth == 0); 431 + current->kmsan_ctx.depth--; 432 + } 433 + EXPORT_SYMBOL(kmsan_enable_current); 434 + 435 + void kmsan_disable_current(void) 436 + { 437 + current->kmsan_ctx.depth++; 438 + KMSAN_WARN_ON(current->kmsan_ctx.depth == 0); 439 + } 440 + EXPORT_SYMBOL(kmsan_disable_current);
+4 -3
mm/kmsan/report.c
··· 8 8 */ 9 9 10 10 #include <linux/console.h> 11 + #include <linux/kmsan.h> 11 12 #include <linux/moduleparam.h> 12 13 #include <linux/stackdepot.h> 13 14 #include <linux/stacktrace.h> ··· 159 158 160 159 if (!kmsan_enabled) 161 160 return; 162 - if (!current->kmsan_ctx.allow_reporting) 161 + if (current->kmsan_ctx.depth) 163 162 return; 164 163 if (!origin) 165 164 return; 166 165 167 - current->kmsan_ctx.allow_reporting = false; 166 + kmsan_disable_current(); 168 167 ua_flags = user_access_save(); 169 168 raw_spin_lock(&kmsan_report_lock); 170 169 pr_err("=====================================================\n"); ··· 217 216 if (panic_on_kmsan) 218 217 panic("kmsan.panic set ...\n"); 219 218 user_access_restore(ua_flags); 220 - current->kmsan_ctx.allow_reporting = true; 219 + kmsan_enable_current(); 221 220 }
+2
tools/objtool/check.c
··· 1202 1202 "__sanitizer_cov_trace_switch", 1203 1203 /* KMSAN */ 1204 1204 "kmsan_copy_to_user", 1205 + "kmsan_disable_current", 1206 + "kmsan_enable_current", 1205 1207 "kmsan_report", 1206 1208 "kmsan_unpoison_entry_regs", 1207 1209 "kmsan_unpoison_memory",