Re: [PATCH v3 4/4] add listmount(2) syscall

From: Ian Kent
Date: Thu Oct 05 2023 - 10:40:45 EST


On 5/10/23 12:01, Miklos Szeredi wrote:
On Wed, 4 Oct 2023 at 21:38, Paul Moore <paul@xxxxxxxxxxxxxx> wrote:
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;
Hmm. Why is this specific to listing mounts (i.e. why doesn't readdir
have a similar filter)?

Also why hasn't this come up with regards to the proc interfaces that
list mounts?

The proc interfaces essentially use <mount namespace>->list to provide

the mounts that can be seen so it's filtered by mount namespace of the

task that's doing the open().


See fs/namespace.c:mnt_list_next() and just below the m_start(), m_next(),

etc.


Ian


I just want to understand the big picture here.

Thanks,
Miklos