Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

libfs: fix get_stashed_dentry()

get_stashed_dentry() tries to optimistically retrieve a stashed dentry
from a provided location. It needs to ensure to hold rcu lock before it
dereference the stashed location to prevent UAF issues. Use
rcu_dereference() instead of READ_ONCE() it's effectively equivalent
with some lockdep bells and whistles and it communicates clearly that
this expects rcu protection.

Link: https://lore.kernel.org/r/20240906-vfs-hotfix-5959800ffa68@brauner
Fixes: 07fd7c329839 ("libfs: add path_from_stashed()")
Reported-by: syzbot+f82b36bffae7ef78b6a7@syzkaller.appspotmail.com
Fixes: syzbot+f82b36bffae7ef78b6a7@syzkaller.appspotmail.com
Reported-by: syzbot+cbe4b96e1194b0e34db6@syzkaller.appspotmail.com
Fixes: syzbot+cbe4b96e1194b0e34db6@syzkaller.appspotmail.com
Signed-off-by: Christian Brauner <brauner@kernel.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

Christian Brauner and committed by
Linus Torvalds
4e32c25b b831f83e

+3 -3
+3 -3
fs/libfs.c
··· 2117 2117 } 2118 2118 EXPORT_SYMBOL(simple_inode_init_ts); 2119 2119 2120 - static inline struct dentry *get_stashed_dentry(struct dentry *stashed) 2120 + static inline struct dentry *get_stashed_dentry(struct dentry **stashed) 2121 2121 { 2122 2122 struct dentry *dentry; 2123 2123 2124 2124 guard(rcu)(); 2125 - dentry = READ_ONCE(stashed); 2125 + dentry = rcu_dereference(*stashed); 2126 2126 if (!dentry) 2127 2127 return NULL; 2128 2128 if (!lockref_get_not_dead(&dentry->d_lockref)) ··· 2219 2219 const struct stashed_operations *sops = mnt->mnt_sb->s_fs_info; 2220 2220 2221 2221 /* See if dentry can be reused. */ 2222 - path->dentry = get_stashed_dentry(*stashed); 2222 + path->dentry = get_stashed_dentry(stashed); 2223 2223 if (path->dentry) { 2224 2224 sops->put_data(data); 2225 2225 goto out_path;