From: Boqun Feng <boqun.feng@gmail.com>
To: Waiman Long <llong@redhat.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>,
Peter Zijlstra <peterz@infradead.org>,
Ingo Molnar <mingo@redhat.com>, Will Deacon <will@kernel.org>,
linux-kernel@vger.kernel.org, Jann Horn <jannh@google.com>
Subject: Re: [PATCH] locking/mutex: Add debug code to help catching violation of mutex lifetime rule
Date: Fri, 11 Jul 2025 21:20:52 -0700 [thread overview]
Message-ID: <aHHipJuS1yyhhkbT@tardis-2.local> (raw)
In-Reply-To: <cad83f32-d1ed-4885-8ed1-c65e5683237e@redhat.com>
On Fri, Jul 11, 2025 at 11:16:43PM -0400, Waiman Long wrote:
> > > > > I think this may also give us a good chance of finding more bugs, one of
> > > > > the reasons is that raw_spin_unlock_irqrestore_wake() has a
> > > > > preempt_enable() at last, which may trigger a context switch.
> > > > >
> > > > > Regards,
> > > > > Boqun
> > > > I think this is a good idea. We should extend that to add the check in
> > > > rwsem as well. Will a post a patch to do that.
> > > Digging into it some more, I think adding kasan_check_byte() may not be
> > > necessary. If KASAN is enabled, it will instrument the locking code
> > > including __mutex_unlock_slowpath(). I checked the generated assembly code,
> > > it has 2 __kasan_check_read() and 4 __kasan_check_write() calls. Adding an
> > The point is we want to check the memory at the end of
> > __mutex_unlock_slowpath(), so it's an extra checking.
>
> It is likely that the instrumented kasan_check* calls can be invoked near
> the beginning when the lock is first accessed, as I don't see any
> kasan_check*() around the inlined raw_spin_unlock_irqrestore_wake() call.
>
One thing to notice is that __kasan_check_{read,write}() are the
instrument of atomic operations (because compiler cannot genenarte the
instrument for asm), try_cmpxchg() would instrument two
kasan_check_write()s and atomic_long_read() would instrument one
kasan_check_read(), and we have 2 try_cmpxchg() and 2 atomic_long_read()
in __mutex_unlock_slowpath(), that's why you saw 4 kasan_check_write()
and 2 kasan_check_read().
Compiler intrumentation is using function like:
__asan_report_store8_noabort()
__asan_report_load8_noabort()
And I checked the asmebly code of __mutex_unlock_slowpath(), and it
turns out it does instrument the memory operations on stack:
3b1c: 94000000 bl 0x3b1c <__mutex_unlock_slowpath+0x188>
0000000000003b1c: R_AARCH64_CALL26 wake_up_q
3b20: 52800028 mov w8, #0x1 // =1
3b24: f9000be8 str x8, [sp, #0x10]
3b28: 38776b08 ldrb w8, [x24, x23]
3b2c: 34000068 cbz w8, 0x3b38 <__mutex_unlock_slowpath+0x1a4>
3b30: aa1303e0 mov x0, x19
3b34: 94000000 bl 0x3b34 <__mutex_unlock_slowpath+0x1a0>
0000000000003b34: R_AARCH64_CALL26 __asan_report_store8_noabort
3b38: f9000ff4 str x20, [sp, #0x18]
^ this is the "head->lastp = &head->first;" in wake_q_init()
and x19 is sp + 0x18, if you believe me ;-)
> So if we want a check at the end, we may have to manually add one.
But yes, we want to add a conceptually check at the very end, as if "the
mutex must be valid in the whole mutex_unlock() function"
>
> >
> > Also since kasan will instrument all memory accesses, what you saw may
> > not be the instrument on "lock" but something else, for example,
> > wake_q_init() in raw_spin_unlock_irqrestore_wake().
>
> The wake_q memory is from stack which I don't believe the compiler will
> generate kasan_check for that. I also don't see any kasan_check*() call when
> the wake_q is being manipulated.
>
See above.
> > Actually, I have 3 extension to the idea:
> >
> > First it occurs to me that we could just put the kasan_check_byte() at
> > the outermost thing, for example, mutex_unlock().
> >
> > Second I wonder whether kasan has a way to tag a pointer parameter of a
> > function, for example for mutex_unlock():
> >
> > void mutex_unlock(struct mutex * __ref lock)
> > {
> > ...
> > }
> >
> > a kasan_check_byte(lock) will auto generate whenever the function
> > returns.
> >
I'm more curious whether kasan can support this.
> > I actually tried to use __cleanup to implement __ref, like
> >
> > #define __ref __cleanup(kasan_check_byte)
> >
> > but seems the "cleanup" attritube doesn't work on function parameters ;(
> >
> > Third, I went to implement a always_alive():
> >
> > #define always_alive(ptr) \
> > typeof(ptr) __UNIQUE_ID(always_alive_guard) __cleanup(kasan_check_byte) = ptr;
> >
> > and you can use in mutex_unlock():
> >
> > void mutex_unlock(struct mutex *lock)
> > {
> > always_alive(lock);
> > ...
> > }
> >
> > This also guarantee we emit a kasan_check_byte() at the very end.
>
> Adding a kasan_check_byte() test at the end of unlock is a locking specific
> problem that we don't have that many instances where a check is needed. So
> it may not be worth the effort to devise a special mechanism just for that.
> Adding a simple macro to abstract it may be enough. Anyway, it is your call.
>
Well, we do have a lot of cases where a foo() takes a "struct bar *" and
the expectation is the pointer is always valid in foo(), so maybe there
are other usages.
But sure, we can start using always_alive() in lock primitives only at
first.
Regards,
Boqun
> Cheers,
> Longman
>
prev parent reply other threads:[~2025-07-12 4:20 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-07-09 19:39 [PATCH] locking/mutex: Add debug code to help catching violation of mutex lifetime rule Waiman Long
2025-07-11 22:20 ` Boqun Feng
2025-07-11 22:30 ` Linus Torvalds
2025-07-11 23:28 ` Boqun Feng
2025-07-12 0:14 ` Linus Torvalds
2025-07-12 0:42 ` Waiman Long
2025-07-12 1:48 ` Waiman Long
2025-07-12 2:24 ` Boqun Feng
2025-07-12 3:16 ` Waiman Long
2025-07-12 4:20 ` Boqun Feng [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=aHHipJuS1yyhhkbT@tardis-2.local \
--to=boqun.feng@gmail.com \
--cc=jannh@google.com \
--cc=linux-kernel@vger.kernel.org \
--cc=llong@redhat.com \
--cc=mingo@redhat.com \
--cc=peterz@infradead.org \
--cc=torvalds@linux-foundation.org \
--cc=will@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.