vfs-6.15-rc3.fixes

-----BEGIN PGP SIGNATURE-----
 
 iHUEABYKAB0WIQRAhzRXHqcMeLMyaSiRxhvAZXjcogUCZ/zJyAAKCRCRxhvAZXjc
 osHWAQDaLE4eduFHRkEm9yiPlzWM7bn5pH0L60nRlWwffae7MQD9EUT3JdGk336X
 zL+LPPYaCGFvgjklhHGdp7GdqsDpiw4=
 =PfIF
 -----END PGP SIGNATURE-----

Merge tag 'vfs-6.15-rc3.fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs

Pull vfs fixes from Christian Brauner:

 - Fix NULL pointer dereference in virtiofs

 - Fix slab OOB access in hfs/hfsplus

 - Only create /proc/fs/netfs when CONFIG_PROC_FS is set

 - Fix getname_flags() to initialize pointer correctly

 - Convert dentry flags to enum

 - Don't allow datadir without lowerdir in overlayfs

 - Use namespace_{lock,unlock} helpers in dissolve_on_fput() instead of
   plain namespace_sem so unmounted mounts are properly cleaned up

 - Skip unnecessary ifs_block_is_uptodate check in iomap

 - Remove an unused forward declaration in overlayfs

 - Fix devpts uid/gid handling after converting to the new mount api

 - Fix afs_dynroot_readdir() to not use the RCU read lock

 - Fix mount_setattr() and open_tree_attr() to not pointlessly do path
   lookup or walk the mount tree if no mount option change has been
   requested

* tag 'vfs-6.15-rc3.fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs:
  fs: use namespace_{lock,unlock} in dissolve_on_fput()
  iomap: skip unnecessary ifs_block_is_uptodate check
  fs: Fix filename init after recent refactoring
  netfs: Only create /proc/fs/netfs with CONFIG_PROC_FS
  mount: ensure we don't pointlessly walk the mount tree
  dcache: convert dentry flag macros to enum
  afs: Fix afs_dynroot_readdir() to not use the RCU read lock
  hfs/hfsplus: fix slab-out-of-bounds in hfs_bnode_read_key
  virtiofs: add filesystem context source name check
  devpts: Fix type for uid and gid params
  ovl: remove unused forward declaration
  ovl: don't allow datadir only
This commit is contained in:
Linus Torvalds 2025-04-14 09:36:16 -07:00
commit 3618002d00
12 changed files with 103 additions and 79 deletions

View File

@ -348,9 +348,9 @@ static int afs_dynroot_readdir(struct file *file, struct dir_context *ctx)
}
if ((unsigned long long)ctx->pos <= AFS_MAX_DYNROOT_CELL_INO) {
rcu_read_lock();
down_read(&net->cells_lock);
ret = afs_dynroot_readdir_cells(net, ctx);
rcu_read_unlock();
up_read(&net->cells_lock);
}
return ret;
}

View File

@ -89,12 +89,12 @@ enum {
};
static const struct fs_parameter_spec devpts_param_specs[] = {
fsparam_u32 ("gid", Opt_gid),
fsparam_gid ("gid", Opt_gid),
fsparam_s32 ("max", Opt_max),
fsparam_u32oct ("mode", Opt_mode),
fsparam_flag ("newinstance", Opt_newinstance),
fsparam_u32oct ("ptmxmode", Opt_ptmxmode),
fsparam_u32 ("uid", Opt_uid),
fsparam_uid ("uid", Opt_uid),
{}
};

View File

@ -1669,6 +1669,9 @@ static int virtio_fs_get_tree(struct fs_context *fsc)
unsigned int virtqueue_size;
int err = -EIO;
if (!fsc->source)
return invalf(fsc, "No source specified");
/* This gets a reference on virtio_fs object. This ptr gets installed
* in fc->iq->priv. Once fuse_conn is going away, it calls ->put()
* to drop the reference to this object.

View File

@ -67,6 +67,12 @@ void hfs_bnode_read_key(struct hfs_bnode *node, void *key, int off)
else
key_len = tree->max_key_len + 1;
if (key_len > sizeof(hfs_btree_key) || key_len < 1) {
memset(key, 0, sizeof(hfs_btree_key));
pr_err("hfs: Invalid key length: %d\n", key_len);
return;
}
hfs_bnode_read(node, key, off, key_len);
}

View File

@ -67,6 +67,12 @@ void hfs_bnode_read_key(struct hfs_bnode *node, void *key, int off)
else
key_len = tree->max_key_len + 2;
if (key_len > sizeof(hfsplus_btree_key) || key_len < 1) {
memset(key, 0, sizeof(hfsplus_btree_key));
pr_err("hfsplus: Invalid key length: %d\n", key_len);
return;
}
hfs_bnode_read(node, key, off, key_len);
}

View File

@ -259,7 +259,7 @@ static void iomap_adjust_read_range(struct inode *inode, struct folio *folio,
}
/* truncate len if we find any trailing uptodate block(s) */
for ( ; i <= last; i++) {
while (++i <= last) {
if (ifs_block_is_uptodate(ifs, i)) {
plen -= (last - i + 1) * block_size;
last = i - 1;

View File

@ -125,9 +125,9 @@
#define EMBEDDED_NAME_MAX (PATH_MAX - offsetof(struct filename, iname))
static inline void initname(struct filename *name)
static inline void initname(struct filename *name, const char __user *uptr)
{
name->uptr = NULL;
name->uptr = uptr;
name->aname = NULL;
atomic_set(&name->refcnt, 1);
}
@ -210,7 +210,7 @@ getname_flags(const char __user *filename, int flags)
return ERR_PTR(-ENAMETOOLONG);
}
}
initname(result);
initname(result, filename);
audit_getname(result);
return result;
}
@ -268,7 +268,7 @@ struct filename *getname_kernel(const char * filename)
return ERR_PTR(-ENAMETOOLONG);
}
memcpy((char *)result->name, filename, len);
initname(result);
initname(result, NULL);
audit_getname(result);
return result;
}

View File

@ -1830,6 +1830,8 @@ static inline void namespace_lock(void)
down_write(&namespace_sem);
}
DEFINE_GUARD(namespace_lock, struct rw_semaphore *, namespace_lock(), namespace_unlock())
enum umount_tree_flags {
UMOUNT_SYNC = 1,
UMOUNT_PROPAGATE = 2,
@ -2383,7 +2385,7 @@ void dissolve_on_fput(struct vfsmount *mnt)
return;
}
scoped_guard(rwsem_write, &namespace_sem) {
scoped_guard(namespace_lock, &namespace_sem) {
ns = m->mnt_ns;
if (!must_dissolve(ns))
return;
@ -5189,8 +5191,8 @@ static void finish_mount_kattr(struct mount_kattr *kattr)
mnt_idmap_put(kattr->mnt_idmap);
}
static int copy_mount_setattr(struct mount_attr __user *uattr, size_t usize,
struct mount_kattr *kattr)
static int wants_mount_setattr(struct mount_attr __user *uattr, size_t usize,
struct mount_kattr *kattr)
{
int ret;
struct mount_attr attr;
@ -5213,9 +5215,13 @@ static int copy_mount_setattr(struct mount_attr __user *uattr, size_t usize,
if (attr.attr_set == 0 &&
attr.attr_clr == 0 &&
attr.propagation == 0)
return 0;
return 0; /* Tell caller to not bother. */
return build_mount_kattr(&attr, usize, kattr);
ret = build_mount_kattr(&attr, usize, kattr);
if (ret < 0)
return ret;
return 1;
}
SYSCALL_DEFINE5(mount_setattr, int, dfd, const char __user *, path,
@ -5247,8 +5253,8 @@ SYSCALL_DEFINE5(mount_setattr, int, dfd, const char __user *, path,
if (flags & AT_RECURSIVE)
kattr.kflags |= MOUNT_KATTR_RECURSE;
err = copy_mount_setattr(uattr, usize, &kattr);
if (err)
err = wants_mount_setattr(uattr, usize, &kattr);
if (err <= 0)
return err;
err = user_path_at(dfd, path, kattr.lookup_flags, &target);
@ -5282,15 +5288,17 @@ SYSCALL_DEFINE5(open_tree_attr, int, dfd, const char __user *, filename,
if (flags & AT_RECURSIVE)
kattr.kflags |= MOUNT_KATTR_RECURSE;
ret = copy_mount_setattr(uattr, usize, &kattr);
if (ret)
ret = wants_mount_setattr(uattr, usize, &kattr);
if (ret < 0)
return ret;
ret = do_mount_setattr(&file->f_path, &kattr);
if (ret)
return ret;
if (ret) {
ret = do_mount_setattr(&file->f_path, &kattr);
if (ret)
return ret;
finish_mount_kattr(&kattr);
finish_mount_kattr(&kattr);
}
}
fd = get_unused_fd_flags(flags & O_CLOEXEC);

View File

@ -127,11 +127,13 @@ static int __init netfs_init(void)
if (mempool_init_slab_pool(&netfs_subrequest_pool, 100, netfs_subrequest_slab) < 0)
goto error_subreqpool;
#ifdef CONFIG_PROC_FS
if (!proc_mkdir("fs/netfs", NULL))
goto error_proc;
if (!proc_create_seq("fs/netfs/requests", S_IFREG | 0444, NULL,
&netfs_requests_seq_ops))
goto error_procfile;
#endif
#ifdef CONFIG_FSCACHE_STATS
if (!proc_create_single("fs/netfs/stats", S_IFREG | 0444, NULL,
netfs_stats_show))
@ -144,9 +146,11 @@ static int __init netfs_init(void)
return 0;
error_fscache:
#ifdef CONFIG_PROC_FS
error_procfile:
remove_proc_subtree("fs/netfs", NULL);
error_proc:
#endif
mempool_exit(&netfs_subrequest_pool);
error_subreqpool:
kmem_cache_destroy(netfs_subrequest_slab);

View File

@ -541,8 +541,6 @@ int ovl_set_metacopy_xattr(struct ovl_fs *ofs, struct dentry *d,
bool ovl_is_metacopy_dentry(struct dentry *dentry);
char *ovl_get_redirect_xattr(struct ovl_fs *ofs, const struct path *path, int padding);
int ovl_ensure_verity_loaded(struct path *path);
int ovl_get_verity_xattr(struct ovl_fs *ofs, const struct path *path,
u8 *digest_buf, int *buf_length);
int ovl_validate_verity(struct ovl_fs *ofs,
struct path *metapath,
struct path *datapath);

View File

@ -1138,6 +1138,11 @@ static struct ovl_entry *ovl_get_lowerstack(struct super_block *sb,
return ERR_PTR(-EINVAL);
}
if (ctx->nr == ctx->nr_data) {
pr_err("at least one non-data lowerdir is required\n");
return ERR_PTR(-EINVAL);
}
err = -EINVAL;
for (i = 0; i < ctx->nr; i++) {
l = &ctx->lower[i];

View File

@ -173,65 +173,59 @@ struct dentry_operations {
*/
/* d_flags entries */
#define DCACHE_OP_HASH BIT(0)
#define DCACHE_OP_COMPARE BIT(1)
#define DCACHE_OP_REVALIDATE BIT(2)
#define DCACHE_OP_DELETE BIT(3)
#define DCACHE_OP_PRUNE BIT(4)
enum dentry_flags {
DCACHE_OP_HASH = BIT(0),
DCACHE_OP_COMPARE = BIT(1),
DCACHE_OP_REVALIDATE = BIT(2),
DCACHE_OP_DELETE = BIT(3),
DCACHE_OP_PRUNE = BIT(4),
/*
* This dentry is possibly not currently connected to the dcache tree,
* in which case its parent will either be itself, or will have this
* flag as well. nfsd will not use a dentry with this bit set, but will
* first endeavour to clear the bit either by discovering that it is
* connected, or by performing lookup operations. Any filesystem which
* supports nfsd_operations MUST have a lookup function which, if it
* finds a directory inode with a DCACHE_DISCONNECTED dentry, will
* d_move that dentry into place and return that dentry rather than the
* passed one, typically using d_splice_alias.
*/
DCACHE_DISCONNECTED = BIT(5),
DCACHE_REFERENCED = BIT(6), /* Recently used, don't discard. */
DCACHE_DONTCACHE = BIT(7), /* Purge from memory on final dput() */
DCACHE_CANT_MOUNT = BIT(8),
DCACHE_GENOCIDE = BIT(9),
DCACHE_SHRINK_LIST = BIT(10),
DCACHE_OP_WEAK_REVALIDATE = BIT(11),
/*
* this dentry has been "silly renamed" and has to be deleted on the
* last dput()
*/
DCACHE_NFSFS_RENAMED = BIT(12),
DCACHE_FSNOTIFY_PARENT_WATCHED = BIT(13), /* Parent inode is watched by some fsnotify listener */
DCACHE_DENTRY_KILLED = BIT(14),
DCACHE_MOUNTED = BIT(15), /* is a mountpoint */
DCACHE_NEED_AUTOMOUNT = BIT(16), /* handle automount on this dir */
DCACHE_MANAGE_TRANSIT = BIT(17), /* manage transit from this dirent */
DCACHE_LRU_LIST = BIT(18),
DCACHE_ENTRY_TYPE = (7 << 19), /* bits 19..21 are for storing type: */
DCACHE_MISS_TYPE = (0 << 19), /* Negative dentry */
DCACHE_WHITEOUT_TYPE = (1 << 19), /* Whiteout dentry (stop pathwalk) */
DCACHE_DIRECTORY_TYPE = (2 << 19), /* Normal directory */
DCACHE_AUTODIR_TYPE = (3 << 19), /* Lookupless directory (presumed automount) */
DCACHE_REGULAR_TYPE = (4 << 19), /* Regular file type */
DCACHE_SPECIAL_TYPE = (5 << 19), /* Other file type */
DCACHE_SYMLINK_TYPE = (6 << 19), /* Symlink */
DCACHE_NOKEY_NAME = BIT(22), /* Encrypted name encoded without key */
DCACHE_OP_REAL = BIT(23),
DCACHE_PAR_LOOKUP = BIT(24), /* being looked up (with parent locked shared) */
DCACHE_DENTRY_CURSOR = BIT(25),
DCACHE_NORCU = BIT(26), /* No RCU delay for freeing */
};
#define DCACHE_DISCONNECTED BIT(5)
/* This dentry is possibly not currently connected to the dcache tree, in
* which case its parent will either be itself, or will have this flag as
* well. nfsd will not use a dentry with this bit set, but will first
* endeavour to clear the bit either by discovering that it is connected,
* or by performing lookup operations. Any filesystem which supports
* nfsd_operations MUST have a lookup function which, if it finds a
* directory inode with a DCACHE_DISCONNECTED dentry, will d_move that
* dentry into place and return that dentry rather than the passed one,
* typically using d_splice_alias. */
#define DCACHE_REFERENCED BIT(6) /* Recently used, don't discard. */
#define DCACHE_DONTCACHE BIT(7) /* Purge from memory on final dput() */
#define DCACHE_CANT_MOUNT BIT(8)
#define DCACHE_GENOCIDE BIT(9)
#define DCACHE_SHRINK_LIST BIT(10)
#define DCACHE_OP_WEAK_REVALIDATE BIT(11)
#define DCACHE_NFSFS_RENAMED BIT(12)
/* this dentry has been "silly renamed" and has to be deleted on the last
* dput() */
#define DCACHE_FSNOTIFY_PARENT_WATCHED BIT(13)
/* Parent inode is watched by some fsnotify listener */
#define DCACHE_DENTRY_KILLED BIT(14)
#define DCACHE_MOUNTED BIT(15) /* is a mountpoint */
#define DCACHE_NEED_AUTOMOUNT BIT(16) /* handle automount on this dir */
#define DCACHE_MANAGE_TRANSIT BIT(17) /* manage transit from this dirent */
#define DCACHE_MANAGED_DENTRY \
(DCACHE_MOUNTED|DCACHE_NEED_AUTOMOUNT|DCACHE_MANAGE_TRANSIT)
#define DCACHE_LRU_LIST BIT(18)
#define DCACHE_ENTRY_TYPE (7 << 19) /* bits 19..21 are for storing type: */
#define DCACHE_MISS_TYPE (0 << 19) /* Negative dentry */
#define DCACHE_WHITEOUT_TYPE (1 << 19) /* Whiteout dentry (stop pathwalk) */
#define DCACHE_DIRECTORY_TYPE (2 << 19) /* Normal directory */
#define DCACHE_AUTODIR_TYPE (3 << 19) /* Lookupless directory (presumed automount) */
#define DCACHE_REGULAR_TYPE (4 << 19) /* Regular file type */
#define DCACHE_SPECIAL_TYPE (5 << 19) /* Other file type */
#define DCACHE_SYMLINK_TYPE (6 << 19) /* Symlink */
#define DCACHE_NOKEY_NAME BIT(22) /* Encrypted name encoded without key */
#define DCACHE_OP_REAL BIT(23)
#define DCACHE_PAR_LOOKUP BIT(24) /* being looked up (with parent locked shared) */
#define DCACHE_DENTRY_CURSOR BIT(25)
#define DCACHE_NORCU BIT(26) /* No RCU delay for freeing */
extern seqlock_t rename_lock;
/*