On Thu, Sep 28, 2023 at 9:04 AM Miklos Szeredi <mszeredi@xxxxxxxxxx> wrote: > > Add way to query the children of a particular mount. This is a more > flexible way to iterate the mount tree than having to parse the complete > /proc/self/mountinfo. > > Lookup the mount by the new 64bit mount ID. If a mount needs to be queried > based on path, then statx(2) can be used to first query the mount ID > belonging to the path. > > Return an array of new (64bit) mount ID's. Without privileges only mounts > are listed which are reachable from the task's root. > > Signed-off-by: Miklos Szeredi <mszeredi@xxxxxxxxxx> > --- > arch/x86/entry/syscalls/syscall_32.tbl | 1 + > arch/x86/entry/syscalls/syscall_64.tbl | 1 + > fs/namespace.c | 69 ++++++++++++++++++++++++++ > include/linux/syscalls.h | 3 ++ > include/uapi/asm-generic/unistd.h | 5 +- > include/uapi/linux/mount.h | 3 ++ > 6 files changed, 81 insertions(+), 1 deletion(-) ... > diff --git a/fs/namespace.c b/fs/namespace.c > index 3326ba2b2810..050e2d2af110 100644 > --- a/fs/namespace.c > +++ b/fs/namespace.c > @@ -4970,6 +4970,75 @@ SYSCALL_DEFINE4(statmount, const struct __mount_arg __user *, req, > return ret; > } > > +static long do_listmount(struct vfsmount *mnt, u64 __user *buf, size_t bufsize, > + const struct path *root, unsigned int flags) > +{ > + struct mount *r, *m = real_mount(mnt); > + struct path rootmnt = { > + .mnt = root->mnt, > + .dentry = root->mnt->mnt_root > + }; > + long ctr = 0; > + bool reachable_only = true; > + int err; > + > + err = security_sb_statfs(mnt->mnt_root); > + if (err) > + return err; > + > + if (flags & LISTMOUNT_UNREACHABLE) { > + if (!capable(CAP_SYS_ADMIN)) > + return -EPERM; > + reachable_only = false; > + } > + > + if (reachable_only && !is_path_reachable(m, mnt->mnt_root, &rootmnt)) > + return capable(CAP_SYS_ADMIN) ? 0 : -EPERM; > + > + list_for_each_entry(r, &m->mnt_mounts, mnt_child) { > + if (reachable_only && > + !is_path_reachable(r, r->mnt.mnt_root, root)) > + continue; I believe we would want to move the security_sb_statfs() call from above to down here; something like this I think ... err = security_sb_statfs(r->mnt.mnt_root); if (err) /* if we can't access the mount, pretend it doesn't exist */ continue; > + if (ctr >= bufsize) > + return -EOVERFLOW; > + if (put_user(r->mnt_id_unique, buf + ctr)) > + return -EFAULT; > + ctr++; > + if (ctr < 0) > + return -ERANGE; > + } > + return ctr; > +} -- paul-moore.com