Commit c2459ce0 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'vfs-6.8-rc1.fixes' of gitolite.kernel.org:pub/scm/linux/kernel/git/vfs/vfs

Pull vfs fixes from Christian Brauner:
 "This contains two fixes for the current merge window. The listmount
  changes that you requested and a fix for a fsnotify performance
  regression:

   - The proposed listmount changes are currently under my authorship. I
     wasn't sure whether you'd wanted to be author as the patch wasn't
     signed off. If you do I'm happy if you just apply your own patch.

     I've tested the patch with my sh4 cross-build setup. And confirmed
     that a) the build failure with sh on current upstream is
     reproducible and that b) the proposed patch fixes the build
     failure. That should only leave the task of fixing put_user on sh.

   - The fsnotify regression was caused by moving one of the hooks out
     of the security hook in preparation for other fsnotify work. This
     meant that CONFIG_SECURITY would have compiled out the fsnotify
     hook before but didn't do so now.

     That lead to up to 6% performance regression in some io_uring
     workloads that compile all fsnotify and security checks out. Fix
     this by making sure that the relevant hooks are covered by the
     already existing CONFIG_FANOTIFY_ACCESS_PERMISSIONS where the
     relevant hook belongs"

* tag 'vfs-6.8-rc1.fixes' of gitolite.kernel.org:pub/scm/linux/kernel/git/vfs/vfs:
  fs: rework listmount() implementation
  fsnotify: compile out fsnotify permission hooks if !FANOTIFY_ACCESS_PERMISSIONS
parents 7f5e47f7 ba5afb9a
......@@ -5042,13 +5042,12 @@ static struct mount *listmnt_next(struct mount *curr)
return node_to_mount(rb_next(&curr->mnt_node));
}
static ssize_t do_listmount(struct mount *first, struct path *orig, u64 mnt_id,
u64 __user *buf, size_t bufsize,
const struct path *root)
static ssize_t do_listmount(struct mount *first, struct path *orig,
u64 mnt_parent_id, u64 __user *mnt_ids,
size_t nr_mnt_ids, const struct path *root)
{
struct mount *r;
ssize_t ctr;
int err;
ssize_t ret;
/*
* Don't trigger audit denials. We just want to determine what
......@@ -5058,50 +5057,57 @@ static ssize_t do_listmount(struct mount *first, struct path *orig, u64 mnt_id,
!ns_capable_noaudit(&init_user_ns, CAP_SYS_ADMIN))
return -EPERM;
err = security_sb_statfs(orig->dentry);
if (err)
return err;
ret = security_sb_statfs(orig->dentry);
if (ret)
return ret;
for (ctr = 0, r = first; r && ctr < bufsize; r = listmnt_next(r)) {
if (r->mnt_id_unique == mnt_id)
for (ret = 0, r = first; r && nr_mnt_ids; r = listmnt_next(r)) {
if (r->mnt_id_unique == mnt_parent_id)
continue;
if (!is_path_reachable(r, r->mnt.mnt_root, orig))
continue;
ctr = array_index_nospec(ctr, bufsize);
if (put_user(r->mnt_id_unique, buf + ctr))
if (put_user(r->mnt_id_unique, mnt_ids))
return -EFAULT;
if (check_add_overflow(ctr, 1, &ctr))
return -ERANGE;
mnt_ids++;
nr_mnt_ids--;
ret++;
}
return ctr;
return ret;
}
SYSCALL_DEFINE4(listmount, const struct mnt_id_req __user *, req,
u64 __user *, buf, size_t, bufsize, unsigned int, flags)
SYSCALL_DEFINE4(listmount, const struct mnt_id_req __user *, req, u64 __user *,
mnt_ids, size_t, nr_mnt_ids, unsigned int, flags)
{
struct mnt_namespace *ns = current->nsproxy->mnt_ns;
struct mnt_id_req kreq;
struct mount *first;
struct path root, orig;
u64 mnt_id, last_mnt_id;
u64 mnt_parent_id, last_mnt_id;
const size_t maxcount = (size_t)-1 >> 3;
ssize_t ret;
if (flags)
return -EINVAL;
if (unlikely(nr_mnt_ids > maxcount))
return -EFAULT;
if (!access_ok(mnt_ids, nr_mnt_ids * sizeof(*mnt_ids)))
return -EFAULT;
ret = copy_mnt_id_req(req, &kreq);
if (ret)
return ret;
mnt_id = kreq.mnt_id;
mnt_parent_id = kreq.mnt_id;
last_mnt_id = kreq.param;
down_read(&namespace_sem);
get_fs_root(current->fs, &root);
if (mnt_id == LSMT_ROOT) {
if (mnt_parent_id == LSMT_ROOT) {
orig = root;
} else {
ret = -ENOENT;
orig.mnt = lookup_mnt_in_ns(mnt_id, ns);
orig.mnt = lookup_mnt_in_ns(mnt_parent_id, ns);
if (!orig.mnt)
goto err;
orig.dentry = orig.mnt->mnt_root;
......@@ -5111,7 +5117,7 @@ SYSCALL_DEFINE4(listmount, const struct mnt_id_req __user *, req,
else
first = mnt_find_id_at(ns, last_mnt_id + 1);
ret = do_listmount(first, &orig, mnt_id, buf, bufsize, &root);
ret = do_listmount(first, &orig, mnt_parent_id, mnt_ids, nr_mnt_ids, &root);
err:
path_put(&root);
up_read(&namespace_sem);
......
......@@ -100,6 +100,7 @@ static inline int fsnotify_file(struct file *file, __u32 mask)
return fsnotify_parent(path->dentry, mask, path, FSNOTIFY_EVENT_PATH);
}
#ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS
/*
* fsnotify_file_area_perm - permission hook before access to file range
*/
......@@ -145,6 +146,24 @@ static inline int fsnotify_open_perm(struct file *file)
return fsnotify_file(file, FS_OPEN_PERM);
}
#else
static inline int fsnotify_file_area_perm(struct file *file, int perm_mask,
const loff_t *ppos, size_t count)
{
return 0;
}
static inline int fsnotify_file_perm(struct file *file, int perm_mask)
{
return 0;
}
static inline int fsnotify_open_perm(struct file *file)
{
return 0;
}
#endif
/*
* fsnotify_link_count - inode's link count changed
*/
......
......@@ -414,7 +414,7 @@ asmlinkage long sys_statmount(const struct mnt_id_req __user *req,
struct statmount __user *buf, size_t bufsize,
unsigned int flags);
asmlinkage long sys_listmount(const struct mnt_id_req __user *req,
u64 __user *buf, size_t bufsize,
u64 __user *mnt_ids, size_t nr_mnt_ids,
unsigned int flags);
asmlinkage long sys_truncate(const char __user *path, long length);
asmlinkage long sys_ftruncate(unsigned int fd, unsigned long length);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment