Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

KMSAN doesn't work with CONFIG_DEBUG_LOCK_ALLOC=y #94

Open
ramosian-glider opened this issue Jun 18, 2024 · 2 comments
Open

KMSAN doesn't work with CONFIG_DEBUG_LOCK_ALLOC=y #94

ramosian-glider opened this issue Jun 18, 2024 · 2 comments
Assignees

Comments

@ramosian-glider
Copy link
Member

ramosian-glider commented Jun 18, 2024

As pointed out at https://lore.kernel.org/lkml/CANpmjNOc4Z6Qy_L3pjuW84BOxoiqXgLC1tWbJuZwRUZqs2ioMA@mail.gmail.com/T/, KMSAN hangs at boot time if CONFIG_DEBUG_LOCK_ALLOC is enabled:

(gdb) 
0xffffffff825a0cd4	106		return in_task() ? &current->kmsan_ctx : raw_cpu_ptr(&kmsan_percpu_ctx);
(gdb) bt
#0  0xffffffff825a0cd4 in kmsan_get_context () at mm/kmsan/kmsan.h:106
#1  __msan_get_context_state () at mm/kmsan/instrumentation.c:331
#2  0xffffffff8185bea0 in lock_acquire (lock=0xffffffff8afcad60 <rcu_sched_lock_map>, subclass=0, trylock=0, read=2, check=0, nest_lock=0x0 <fixed_percpu_data>, ip=18446744071601531329) at kernel/locking/lockdep.c:5722
#3  0xffffffff825a29dd in rcu_lock_acquire (map=<optimized out>) at ./include/linux/rcupdate.h:329
#4  rcu_read_lock_sched () at ./include/linux/rcupdate.h:873
#5  pfn_valid (pfn=<optimized out>) at ./include/linux/mmzone.h:2022
#6  kmsan_virt_addr_valid (addr=0xffff88807fca1b40, addr@entry=0xffffffff825a29c1 <virt_to_page_or_null+193>) at ./arch/x86/include/asm/kmsan.h:94
#7  virt_to_page_or_null (vaddr=vaddr@entry=0xffff88807fca1b40) at mm/kmsan/shadow.c:75
#8  0xffffffff825a2870 in kmsan_get_metadata (address=0xffff88807fca1b40, is_origin=false) at mm/kmsan/shadow.c:143
#9  0xffffffff825a2695 in kmsan_get_shadow_origin_ptr (address=0xffff88807fca1b40, size=4, store=false) at mm/kmsan/shadow.c:97
#10 0xffffffff8259fff4 in get_shadow_origin_ptr (addr=0xffffffff8afcad60 <rcu_sched_lock_map>, size=4, store=false) at mm/kmsan/instrumentation.c:36
#11 __msan_metadata_ptr_for_load_4 (addr=0xffffffff8afcad60 <rcu_sched_lock_map>) at mm/kmsan/instrumentation.c:91
#12 0xffffffff8197040a in arch_atomic_read (v=0xffffffff8afcad60 <rcu_sched_lock_map>) at ./arch/x86/include/asm/atomic.h:23
#13 raw_atomic_read (v=0xffffffff8afcad60 <rcu_sched_lock_map>) at ./include/linux/atomic/atomic-arch-fallback.h:457
#14 rcu_dynticks_curr_cpu_in_eqs () at ./include/linux/context_tracking.h:122
#15 rcu_is_watching () at kernel/rcu/tree.c:724
#16 0xffffffff8185bec8 in trace_lock_acquire (lock=<optimized out>, subclass=<optimized out>, trylock=<optimized out>, read=<optimized out>, check=<optimized out>, next_lock=<optimized out>, ip=<optimized out>) at ./include/trace/events/lock.h:24
#17 lock_acquire (lock=0xffffffff8afcad60 <rcu_sched_lock_map>, subclass=0, trylock=0, read=2, check=0, nest_lock=0x0 <fixed_percpu_data>, ip=18446744071601531329) at kernel/locking/lockdep.c:5725
#18 0xffffffff825a29dd in rcu_lock_acquire (map=<optimized out>) at ./include/linux/rcupdate.h:329
#19 rcu_read_lock_sched () at ./include/linux/rcupdate.h:873
#20 pfn_valid (pfn=<optimized out>) at ./include/linux/mmzone.h:2022
#21 kmsan_virt_addr_valid (addr=0xffffffff8ae03c50, addr@entry=0xffffffff825a29c1 <virt_to_page_or_null+193>) at ./arch/x86/include/asm/kmsan.h:94
#22 virt_to_page_or_null (vaddr=vaddr@entry=0xffffffff8ae03c50) at mm/kmsan/shadow.c:75
#23 0xffffffff825a2870 in kmsan_get_metadata (address=0xffffffff8ae03c50, is_origin=false) at mm/kmsan/shadow.c:143
#24 0xffffffff825a2695 in kmsan_get_shadow_origin_ptr (address=0xffffffff8ae03c50, size=8, store=false) at mm/kmsan/shadow.c:97
#25 0xffffffff825a0094 in get_shadow_origin_ptr (addr=0xffffffff8afcad60 <rcu_sched_lock_map>, size=8, store=false) at mm/kmsan/instrumentation.c:36
#26 __msan_metadata_ptr_for_load_8 (addr=0xffffffff8afcad60 <rcu_sched_lock_map>) at mm/kmsan/instrumentation.c:92
#27 0xffffffff81a046c9 in filter_irq_stacks (entries=<optimized out>, nr_entries=4) at kernel/stacktrace.c:397
#28 0xffffffff85dd026b in stack_depot_save_flags (entries=0xffffffff8afcad60 <rcu_sched_lock_map>, nr_entries=0, alloc_flags=0, depot_flags=1) at lib/stackdepot.c:609
#29 0xffffffff85dd0a22 in stack_depot_save (entries=0xffffffff8afcad60 <rcu_sched_lock_map>, nr_entries=0, alloc_flags=0) at lib/stackdepot.c:678
#30 0xffffffff825a09c2 in __msan_poison_alloca (address=0xffffffff8ae03ce0, size=40, descr=<optimized out>) at mm/kmsan/instrumentation.c:285
#31 0xffffffff89e75f87 in __mutex_lock_common (nest_lock=<optimized out>, ww_ctx=0x0 <fixed_percpu_data>, use_ww_ctx=false, lock=<optimized out>, state=<optimized out>, subclass=<optimized out>, ip=<optimized out>) at kernel/locking/mutex.c:578
#32 __mutex_lock (lock=lock@entry=0xffffffff8b009d30 <slab_mutex>, state=state@entry=2, subclass=subclass@entry=0, nest_lock=nest_lock@entry=0x0 <fixed_percpu_data>, ip=18446744071598433441) at kernel/locking/mutex.c:752
#33 0xffffffff89e75f24 in mutex_lock_nested (lock=0xffffffff8b009d30 <slab_mutex>, subclass=0) at kernel/locking/mutex.c:804
#34 0xffffffff822ae4a1 in kmem_cache_create_usercopy (name=0xffffffff8aac3044 "mm_struct", size=2256, align=0, flags=16656, useroffset=0, usersize=0, ctor=0x0 <fixed_percpu_data>) at mm/slab_common.c:297
#35 0xffffffff8b4e879a in mm_cache_init () at kernel/fork.c:3157
#36 0xffffffff8b52bdb2 in mm_core_init () at mm/mm_init.c:2760
#37 0xffffffff8b441e6b in start_kernel () at init/main.c:962
#38 0xffffffff8b471e7e in x86_64_start_reservations (real_mode_data=0x13f30 <exception_stacks+28464> <error: Cannot access memory at address 0x13f30>) at arch/x86/kernel/head64.c:507
#39 0xffffffff8b471d68 in x86_64_start_kernel (real_mode_data=0x13f30 <exception_stacks+28464> <error: Cannot access memory at address 0x13f30>) at arch/x86/kernel/head64.c:488
#40 0xffffffff81457415 in secondary_startup_64 () at arch/x86/kernel/head_64.S:420
#41 0x0000000000000000 in ?? ()
@ramosian-glider ramosian-glider self-assigned this Jun 18, 2024
@dvyukov
Copy link
Collaborator

dvyukov commented Jun 18, 2024

Potentially we can just declare most debug configs as incompatible with KMSAN and prohibit enabling with KMSAN. I afraid there is lots tail (KMEMLEAK, LOCKDEP, well KASAN as well). Since it's not possible to enable all debug configs at once (at least KASAN/KCSAN will require separate builds), we can say that these other bugs configs should be enabled in other debug builds (e.g. with KASAN).

@ramosian-glider
Copy link
Member Author

The following (incomplete) patch:

diff --git a/arch/x86/include/asm/kmsan.h b/arch/x86/include/asm/kmsan.h
index d91b37f5b4bb4..8a25ca008e021 100644
--- a/arch/x86/include/asm/kmsan.h
+++ b/arch/x86/include/asm/kmsan.h
@@ -57,6 +57,8 @@ static inline bool kmsan_phys_addr_valid(unsigned long addr)
                return true;
 }
 
+DECLARE_PER_CPU(bool, reenter_vaddr);
+
 /*
  * Taken from arch/x86/mm/physaddr.c to avoid using an instrumented version.
  */
@@ -64,7 +66,7 @@ static inline bool kmsan_virt_addr_valid(void *addr)
 {
        unsigned long x = (unsigned long)addr;
        unsigned long y = x - __START_KERNEL_map;
-       bool ret;
+       bool ret = false;
 
        /* use the carry flag to determine if x was < __START_KERNEL_map */
        if (unlikely(x > y)) {
@@ -91,7 +93,11 @@ static inline bool kmsan_virt_addr_valid(void *addr)
         * performance guarantees due to being heavily instrumented.
         */
        preempt_disable();
-       ret = pfn_valid(x >> PAGE_SHIFT);
+       if (!this_cpu_read(reenter_vaddr)) {
+               this_cpu_write(reenter_vaddr, true);
+               ret = pfn_valid(x >> PAGE_SHIFT);
+               this_cpu_write(reenter_vaddr, false);
+       }
        preempt_enable_no_resched();
 
        return ret;

fixes the reentrancy problem for lockdep calls in pfn_valid().
(See https://groups.google.com/g/kasan-dev/c/ZBiGzZL36-I/m/WtNuKqP9EQAJ for more context)

However the kernel is still very slow, as we're doing multiple lockdep checks for every memory access.

I think we'd better disable LOCK_DEBUGGING_SUPPORT under KMSAN altogether.

intel-lab-lkp pushed a commit to intel-lab-lkp/linux that referenced this issue Jun 25, 2024
At least on x86 KMSAN is seriously slown down by lockdep, as every
pfn_valid() call (which is done on every instrumented memory access
in the kernel) performs several lockdep checks, all of which, in turn,
perform additional memory accesses and call KMSAN instrumentation.

Right now lockdep overflows the stack under KMSAN, but even if we use
reentrancy counters to avoid the recursion on the KMSAN side, the slowdown
from lockdep remains big enough for the kernel to become unusable.

Reported-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
Closes: google/kmsan#94
Link: https://groups.google.com/g/kasan-dev/c/ZBiGzZL36-I/m/WtNuKqP9EQAJ
Signed-off-by: Alexander Potapenko <glider@google.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants