On Tue, Jul 07, 2026 at 07:33:22AM +0000, [email protected] wrote:
> Thank you for your contribution! Sashiko AI review found 5 potential issue(s)
> to consider:
> - [Critical] dept_key_destroy() synchronously recycles dept_class objects to
> the lockless pool before the RCU grace period completes, causing UAF and list
> traversal corruption for concurrent lockless readers.
> - [High] rwsem_acquire_read and rwsem_acquire incorrectly use ldt_lock(),
> breaking reader-writer dependency tracking and causing false-positive
> deadlocks.
> - [High] ldt_init() is called before the `key` parameter is validated,
> causing DEPT to dereference a garbage pointer if `key` is NULL.
> - [Medium] dept_key_init() and dept_key_destroy() are called on static keys
> before validation, erroneously disabling DEPT or corrupting tracking state.
> - [Low] STATIC_LOCKDEP_MAP_INIT creates double-quoted strings for map names
> due to `#n` stringification in DEPT_MAP_INITIALIZER.
> --
>
> commit 6c1a95ee3182a2a82a1d61196d75acd387d7f3e3
> Author: Byungchul Park <[email protected]>
>
> dept: tie to lockdep and IRQ tracing
>
> This patch integrates DEPT (Dependency Tracker) into the lockdep framework
> and IRQ tracing paths. It modifies various locking primitives and lockdep
> interfaces to initialize and track DEPT maps alongside lockdep maps.
>
> > diff --git a/include/linux/lockdep.h b/include/linux/lockdep.h
> > index 621566345406d..60b17a2ff555f 100644
> > --- a/include/linux/lockdep.h
> > +++ b/include/linux/lockdep.h
> [ ... ]
> > @@ -428,7 +431,8 @@ enum xhlock_context_t {
> > * Note that _name must not be NULL.
> > */
> > #define STATIC_LOCKDEP_MAP_INIT(_name, _key) \
> > - { .name = (_name), .key = (void *)(_key), }
> > + { .name = (_name), .key = (void *)(_key), \
> > + .dmap = DEPT_MAP_INITIALIZER(_name, _key) }
>
> [Severity: Low]
> Since _name is usually passed as a string literal to
> STATIC_LOCKDEP_MAP_INIT, does passing it to DEPT_MAP_INITIALIZER, which
> uses the stringification operator on its first argument, result in
> double-quoted strings for map names in DEPT's debug output?
I will check it. Thanks.
> [ ... ]
> > -#define rwsem_acquire(l, s, t, i) lock_acquire_exclusive(l, s,
> > t, NULL, i)
> > -#define rwsem_acquire_nest(l, s, t, n, i) lock_acquire_exclusive(l, s,
> > t, n, i)
> > -#define rwsem_acquire_read(l, s, t, i)
> > lock_acquire_shared(l, s, t, NULL, i)
> > -#define rwsem_release(l, i) lock_release(l, i)
> [ ... ]
> > +#define rwsem_acquire(l, s, t, i) \
> > +do { \
> > + ldt_lock(&(l)->dmap, s, t, NULL, i); \
> > + lock_acquire_exclusive(l, s, t, NULL, i); \
> > +} while (0)
> > +#define rwsem_acquire_nest(l, s, t, n, i) \
> > +do { \
> > + ldt_lock(&(l)->dmap, s, t, n, i); \
> > + lock_acquire_exclusive(l, s, t, n, i); \
> > +} while (0)
> > +#define rwsem_acquire_read(l, s, t, i)
> > \
> > +do { \
> > + ldt_lock(&(l)->dmap, s, t, NULL, i); \
> > + lock_acquire_shared(l, s, t, NULL, i); \
> > +} while (0)
>
> [Severity: High]
> Is it intentional that rwsem_acquire_read() uses ldt_lock() instead of
> ldt_rlock(), and rwsem_acquire() uses ldt_lock() instead of ldt_wlock()?
It's intended. rwsem is a queued lock for fairness. So it should be
considered as a normal lock to detect a potential deadlock.
> This appears to mistakenly model a shared lock as an exclusive lock. Does
> this cause DEPT to incorrectly model concurrent read locks as mutually
> exclusive, leading to false-positive circular dependency (deadlock) reports
> when concurrent readers take an rwsem and interact with other locks?
As I told you, rwsem is a queued lock. So this is not true.
> > diff --git a/kernel/locking/lockdep.c b/kernel/locking/lockdep.c
> > index 2d4c5bab5af88..dc97f2753ef81 100644
> > --- a/kernel/locking/lockdep.c
> > +++ b/kernel/locking/lockdep.c
> > @@ -1224,6 +1224,8 @@ void lockdep_register_key(struct lock_class_key *key)
> > struct hlist_head *hash_head;
> > struct lock_class_key *k;
> > unsigned long flags;
> >
> > + dept_key_init(&key->dkey);
> > +
> > if (WARN_ON_ONCE(static_obj(key)))
> > return;
>
> [Severity: Medium]
> In lockdep_register_key(), dept_key_init() is called before the
> static_obj() check. If a static key is improperly passed, lockdep gracefully
> rejects it by warning and returning early.
>
> However, processing a static key in dept_key_init() triggers a DEPT_STOP
> abort. Should the DEPT initialization occur after validating the key?
I will check it.
> [ ... ]
> > @@ -4940,6 +4950,8 @@ void lockdep_init_map_type(struct lockdep_map *lock,
> > const char *name,
> > {
> > int i;
> >
> > + ldt_init(&lock->dmap, &key->dkey, subclass, name);
> > +
> > for (i = 0; i < NR_LOCKDEP_CACHING_CLASSES; i++)
> > lock->class_cache[i] = NULL;
>
> [Severity: High]
> In lockdep_init_map_type(), ldt_init() is called before the parameter
> validation checks for a NULL key further down in the function.
>
> If key is NULL, &key->dkey yields a non-NULL offset pointer. Does DEPT accept
> this garbage pointer in valid_key(), causing a kernel panic when
> check_new_class() dereferences it?
I will check it.
> [ ... ]
> > @@ -6588,6 +6608,8 @@ void lockdep_unregister_key(struct lock_class_key
> > *key)
> > bool found = false;
> > bool need_callback = false;
> >
> > + dept_key_destroy(&key->dkey);
> > +
> > might_sleep();
> >
> > if (WARN_ON_ONCE(static_obj(key)))
> > return;
>
> [Severity: Medium]
> Similarly to lockdep_register_key(), dept_key_destroy() is called here
> unconditionally before the static_obj() check. If a driver incorrectly calls
> dynamic lock destruction on a static key, it eagerly destroys its DEPT state
> while lockdep retains it. Should this also be moved after the static_obj()
> check?
Sure. I will.
> [Severity: Critical]
> Additionally, in dept_key_destroy() called here, the function removes a class
> from the RCU hash table and drops its refcount to 0 via del_class(). This
> recycles the object to the DEPT pool before synchronize_rcu() is called.
No.
del_class() never drops refcount to 0. That happens only through:
disconnect_class()->call_rcu(del_dep_rcu)
// after the grace period
del_dep_rcu()->del_dep()->put_ecxt()->put_class()
del_dep_rcu()->del_dep()->put_wait()->put_class()
So it's safe.
> Can a concurrent lockless reader in hash_lookup_class() traversing the same
> bucket via hlist_for_each_entry_rcu() access this recycled object, leading to
> a use-after-free and hash list corruption?
No.
Byungchul
>
> --
> Sashiko AI review ยท
> https://sashiko.dev/#/patchset/[email protected]?part=4