mirror of
https://github.com/torvalds/linux.git
synced 2026-05-23 06:31:58 +02:00
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:
commit
3618002d00
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
{}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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];
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
/*
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user