From: Linus Torvalds Date: Thu, 30 Jan 2025 17:13:35 +0000 (-0800) Subject: Merge tag 'pull-revalidate' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs X-Git-Tag: v6.14-rc1~38 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=d3d90cc2891c9cf4ecba7b85c0af716ab755c7e5;p=thirdparty%2Flinux.git Merge tag 'pull-revalidate' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs Pull vfs d_revalidate updates from Al Viro: "Provide stable parent and name to ->d_revalidate() instances Most of the filesystem methods where we care about dentry name and parent have their stability guaranteed by the callers; ->d_revalidate() is the major exception. It's easy enough for callers to supply stable values for expected name and expected parent of the dentry being validated. That kills quite a bit of boilerplate in ->d_revalidate() instances, along with a bunch of races where they used to access ->d_name without sufficient precautions" * tag 'pull-revalidate' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs: 9p: fix ->rename_sem exclusion orangefs_d_revalidate(): use stable parent inode and name passed by caller ocfs2_dentry_revalidate(): use stable parent inode and name passed by caller nfs: fix ->d_revalidate() UAF on ->d_name accesses nfs{,4}_lookup_validate(): use stable parent inode passed by caller gfs2_drevalidate(): use stable parent inode and name passed by caller fuse_dentry_revalidate(): use stable parent inode and name passed by caller vfat_revalidate{,_ci}(): use stable parent inode passed by caller exfat_d_revalidate(): use stable parent inode passed by caller fscrypt_d_revalidate(): use stable parent inode passed by caller ceph_d_revalidate(): propagate stable name down into request encoding ceph_d_revalidate(): use stable parent inode passed by caller afs_d_revalidate(): use stable name and parent inode passed by caller Pass parent directory inode and expected name to ->d_revalidate() generic_ci_d_compare(): use shortname_storage ext4 fast_commit: make use of name_snapshot primitives dissolve external_name.u into separate members make take_dentry_name_snapshot() lockless dcache: back inline names with a struct-wrapped array of unsigned long make sure that DNAME_INLINE_LEN is a multiple of word size --- d3d90cc2891c9cf4ecba7b85c0af716ab755c7e5 diff --cc fs/afs/dir.c index a843c36fc4712,e04cffe4beb11..02cbf38e1a776 --- a/fs/afs/dir.c +++ b/fs/afs/dir.c @@@ -597,8 -607,8 +598,8 @@@ static bool afs_lookup_one_filldir(stru * Do a lookup of a single name in a directory * - just returns the FID the dentry name maps to if found */ - static int afs_do_lookup_one(struct inode *dir, struct dentry *dentry, + static int afs_do_lookup_one(struct inode *dir, const struct qstr *name, - struct afs_fid *fid, struct key *key, + struct afs_fid *fid, afs_dataversion_t *_dir_version) { struct afs_super_info *as = dir->i_sb->s_fs_info; @@@ -609,10 -619,10 +610,10 @@@ }; int ret; - _enter("{%lu},%p{%pd},", dir->i_ino, dentry, dentry); + _enter("{%lu},{%.*s},", dir->i_ino, name->len, name->name); /* search the directory */ - ret = afs_dir_iterate(dir, &cookie.ctx, key, _dir_version); + ret = afs_dir_iterate(dir, &cookie.ctx, NULL, _dir_version); if (ret < 0) { _leave(" = %d [iter]", ret); return ret; @@@ -1127,7 -1142,7 +1114,7 @@@ static int afs_d_revalidate(struct inod afs_stat_v(dir, n_reval); /* search the directory for this vnode */ - ret = afs_do_lookup_one(&dir->netfs.inode, dentry, &fid, &dir_version); - ret = afs_do_lookup_one(&dir->netfs.inode, name, &fid, key, &dir_version); ++ ret = afs_do_lookup_one(&dir->netfs.inode, name, &fid, &dir_version); switch (ret) { case 0: /* the filename maps to something */ diff --cc fs/fuse/dir.c index be693a8a10109,3019bc1d9f9de..198862b086ff7 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c @@@ -175,10 -175,11 +175,12 @@@ static void fuse_lookup_init(struct fus memset(outarg, 0, sizeof(struct fuse_entry_out)); args->opcode = FUSE_LOOKUP; args->nodeid = nodeid; -- args->in_numargs = 2; - args->in_args[0].size = name->len; - args->in_args[0].value = name->name; - args->in_args[1].size = 1; - args->in_args[1].value = ""; ++ args->in_numargs = 3; + fuse_set_zero_arg0(args); - args->in_args[1].size = name->len + 1; ++ args->in_args[1].size = name->len; + args->in_args[1].value = name->name; ++ args->in_args[2].size = 1; ++ args->in_args[2].value = ""; args->out_numargs = 1; args->out_args[0].size = sizeof(struct fuse_entry_out); args->out_args[0].value = outarg;