FAILED: patch "[PATCH] locking/lockdep: Avoid potential access of invalid memory in" failed to apply to 5.4-stable tree
Subsystems (2)
[email protected]
maintainerThe patch below does not apply to the 5.4-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From 61cc4534b6550997c97a03759ab46b29d44c0017 Mon Sep 17 00:00:00 2001
From: Waiman Long <[email protected]>
Date: Sun, 2 Jan 2022 21:35:58 -0500
Subject: [PATCH] locking/lockdep: Avoid potential access of invalid memory in
lock_class
It was found that reading /proc/lockdep after a lockdep splat may potentially cause an access to freed memory if lockdep_unregister_key() is called after the splat but before access to /proc/lockdep [1]. This is due to the fact that graph_lock() call in lockdep_unregister_key() fails after the clearing of debug_locks by the splat process.
After lockdep_unregister_key() is called, the lock_name may be freed but the corresponding lock_class structure still have a reference to it. That invalid memory pointer will then be accessed when /proc/lockdep is read by a user and a use-after-free (UAF) error will be reported if KASAN is enabled.
To fix this problem, lockdep_unregister_key() is now modified to always search for a matching key irrespective of the debug_locks state and zap the corresponding lock class if a matching one is found.
[1] https://lore.kernel.org/lkml/[email protected]/
kernel/locking/lockdep.c +15 -9
@@ -6287,7 +6287,13 @@ void lockdep_reset_lock(struct lockdep_map *lock)lockdep_reset_lock_reg (lock); } -/* Unregister a dynamically allocated key. */ +/* +* Unregister a dynamically allocated key. +* +* Unlike lockdep_register_key(), a search is always done to find a matching +* key irrespective of debug_locks to avoid potential invalid access to freed +* memory in lock_class entry. +*/ void lockdep_unregister_key (struct lock_class_key *key) {struct hlist_head *hash_head =keyhashentry (key);
@@ -6302,10 +6308,8 @@ void lockdep_unregister_key(struct lock_class_key *key)return ;raw_local_irq_save (flags); -if (!graph_lock ()) - goto out_irq; +lockdep_lock (); - pf =get_pending_free ();hlist_for_each_entry_rcu (k, hash_head, hash_entry) {if (k == key) {hlist_del_rcu (&k->hash_entry);
@@ -6313,11 +6317,13 @@ void lockdep_unregister_key(struct lock_class_key *key)break ; } } -WARN_ON_ONCE (!found); -__lockdep_free_key_range (pf, key,1 ); -call_rcu_zapped (pf); -graph_unlock (); -out_irq: +WARN_ON_ONCE (!found && debug_locks); +if (found) { + pf =get_pending_free (); +__lockdep_free_key_range (pf, key,1 ); +call_rcu_zapped (pf); + } +lockdep_unlock ();raw_local_irq_restore (flags);/* Wait until is_dynamic_key() has finished accessing k->hash_entry. */