]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
eventfs: Fix use-after-free in eventfs_remove_rec()
authorShuangpeng Bai <shuangpeng.kernel@gmail.com>
Thu, 6 Aug 2026 02:27:19 +0000 (22:27 -0400)
committerSteven Rostedt <rostedt@goodmis.org>
Sat, 8 Aug 2026 14:35:33 +0000 (10:35 -0400)
eventfs_remove_rec() recursively removes the child at the current loop
position. After the recursive call returns, list_for_each_entry() advances
by reading list.next from the removed child.

If free_ei() drops the final reference, release_ei() reuses the list/rcu
union to queue an SRCU callback. The child may be freed before that read.
The eventfs_mutex serializes list updates, but it does not keep the removed
child alive or prevent the SRCU callback from running.

Use list_for_each_entry_safe() to save the next sibling before recursively
removing the current child.

Cc: stable@vger.kernel.org
Fixes: 43aa6f97c2d0 ("eventfs: Get rid of dentry pointers without refcounts")
Link: https://patch.msgid.link/20260806022719.375354-1-shuangpeng.kernel@gmail.com
Signed-off-by: Shuangpeng Bai <shuangpeng.kernel@gmail.com>
Acked-by: Masami Hiramatsu (Google) <mhiramat@kernel.org>
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
fs/tracefs/event_inode.c

index 39c7a34531e8a13dedfa2ca32489fda5194afd10..93bc4f83b73e3fbadb1d6445f2ccafc3a3697af1 100644 (file)
@@ -822,7 +822,7 @@ struct eventfs_inode *eventfs_create_events_dir(const char *name, struct dentry
  */
 static void eventfs_remove_rec(struct eventfs_inode *ei, int level)
 {
-       struct eventfs_inode *ei_child;
+       struct eventfs_inode *ei_child, *tmp;
 
        /*
         * Check recursion depth. It should never be greater than 3:
@@ -835,7 +835,7 @@ static void eventfs_remove_rec(struct eventfs_inode *ei, int level)
                return;
 
        /* search for nested folders or files */
-       list_for_each_entry(ei_child, &ei->children, list)
+       list_for_each_entry_safe(ei_child, tmp, &ei->children, list)
                eventfs_remove_rec(ei_child, level + 1);
 
        list_del_rcu(&ei->list);