On Oct 25, 2023 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. > > Allow listing either > > - immediate child mounts only, or > > - recursively all descendant mounts (depth first). > > 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> > Reviewed-by: Ian Kent <raven@xxxxxxxxxx> > --- > fs/namespace.c | 93 ++++++++++++++++++++++++++++++++++++++ > include/linux/syscalls.h | 3 ++ > include/uapi/linux/mount.h | 9 ++++ > 3 files changed, 105 insertions(+) > > diff --git a/fs/namespace.c b/fs/namespace.c > index a980c250a3a6..0afe2344bba6 100644 > --- a/fs/namespace.c > +++ b/fs/namespace.c > @@ -4958,6 +4958,99 @@ SYSCALL_DEFINE4(statmount, const struct __mount_arg __user *, req, > return ret; > } > > +static struct mount *listmnt_first(struct mount *root) > +{ > + return list_first_entry_or_null(&root->mnt_mounts, struct mount, mnt_child); > +} > + > +static struct mount *listmnt_next(struct mount *curr, struct mount *root, bool recurse) > +{ > + if (recurse) > + return next_mnt(curr, root); > + if (!list_is_head(curr->mnt_child.next, &root->mnt_mounts)) > + return list_next_entry(curr, mnt_child); > + return NULL; > +} > + > +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; > + bool recurse = flags & LISTMOUNT_RECURSIVE; > + 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; > + } Similar to my comment in patch 4/6, please move the LSM call after the capability check. > + if (reachable_only && !is_path_reachable(m, mnt->mnt_root, &rootmnt)) > + return capable(CAP_SYS_ADMIN) ? 0 : -EPERM; > + > + for (r = listmnt_first(m); r; r = listmnt_next(r, m, recurse)) { > + if (reachable_only && > + !is_path_reachable(r, r->mnt.mnt_root, root)) > + 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