fs: prefer kfree_rcu() in fasync_remove_entry()
authorDmitry Antipov <dmantipov@yandex.ru>
Fri, 9 Feb 2024 12:52:19 +0000 (15:52 +0300)
committerChristian Brauner <brauner@kernel.org>
Mon, 12 Feb 2024 10:00:10 +0000 (11:00 +0100)
In 'fasync_remove_entry()', prefer 'kfree_rcu()' over 'call_rcu()' with dummy
'fasync_free_rcu()' callback. This is mostly intended in attempt to fix weird
https://syzkaller.appspot.com/bug?id=6a64ad907e361e49e92d1c4c114128a1bda2ed7f,
where kmemleak may consider 'fa' as unreferenced during RCU grace period. See
https://lore.kernel.org/stable/20230930174657.800551-1-joel@joelfernandes.org
as well. Comments are highly appreciated.

Ever since ae65a5211d90 ("mm/slab: document kfree() as allowed for
kmem_cache_alloc() objects") kfree() can be used for both kmalloc() and
kmem_cache_alloc() so this is no safe.

Do not backport this to stable, please.

Link ae65a5211d90 ("mm/slab: document kfree() as > allowed for kmem_cache_alloc() objects")
Signed-off-by: Dmitry Antipov <dmantipov@yandex.ru>
Link: https://lore.kernel.org/r/20240209125220.330383-1-dmantipov@yandex.ru
Signed-off-by: Christian Brauner <brauner@kernel.org>
fs/fcntl.c

index c80a6acad742fb027a4a990f63ef05d0678736d7..c3e342eb74afa61ee2f427423e28f33c1105c76e 100644 (file)
@@ -846,12 +846,6 @@ int send_sigurg(struct fown_struct *fown)
 static DEFINE_SPINLOCK(fasync_lock);
 static struct kmem_cache *fasync_cache __ro_after_init;
 
-static void fasync_free_rcu(struct rcu_head *head)
-{
-       kmem_cache_free(fasync_cache,
-                       container_of(head, struct fasync_struct, fa_rcu));
-}
-
 /*
  * Remove a fasync entry. If successfully removed, return
  * positive and clear the FASYNC flag. If no entry exists,
@@ -877,7 +871,7 @@ int fasync_remove_entry(struct file *filp, struct fasync_struct **fapp)
                write_unlock_irq(&fa->fa_lock);
 
                *fp = fa->fa_next;
-               call_rcu(&fa->fa_rcu, fasync_free_rcu);
+               kfree_rcu(fa, fa_rcu);
                filp->f_flags &= ~FASYNC;
                result = 1;
                break;