From: Christian Brauner <brauner@xxxxxxxxxx> This patch makes use of the new mnt_ns_id field in struct mnt_id_req to allow users to stat mount entries not in their mount namespace. The rules are the same as listmount(), the user must have CAP_SYS_ADMIN in their user namespace and the target mount namespace must be a child of the current namespace. Co-developed-by: Josef Bacik <josef@xxxxxxxxxxxxxx> Signed-off-by: Christian Brauner <brauner@xxxxxxxxxx> Signed-off-by: Josef Bacik <josef@xxxxxxxxxxxxxx> --- fs/namespace.c | 31 +++++++++++++++++++++++++------ 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/fs/namespace.c b/fs/namespace.c index 1b422fd5f267..6d44537fd78c 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -4977,10 +4977,8 @@ static int statmount_fs_type(struct kstatmount *s, struct seq_file *seq) return 0; } -static void statmount_mnt_ns_id(struct kstatmount *s) +static void statmount_mnt_ns_id(struct kstatmount *s, struct mnt_namespace *ns) { - struct mnt_namespace *ns = current->nsproxy->mnt_ns; - s->sm.mask |= STATMOUNT_MNT_NS_ID; s->sm.mnt_ns_id = ns->seq; } @@ -5082,7 +5080,7 @@ static int do_statmount(struct kstatmount *s) err = statmount_string(s, STATMOUNT_MNT_POINT); if (!err && s->mask & STATMOUNT_MNT_NS_ID) - statmount_mnt_ns_id(s); + statmount_mnt_ns_id(s, ns); if (err) return err; @@ -5199,6 +5197,7 @@ SYSCALL_DEFINE4(statmount, const struct mnt_id_req __user *, req, struct statmount __user *, buf, size_t, bufsize, unsigned int, flags) { + struct mnt_namespace *ns __free(mnt_ns_release) = NULL; struct vfsmount *mnt; struct mnt_id_req kreq; struct kstatmount ks; @@ -5213,13 +5212,28 @@ SYSCALL_DEFINE4(statmount, const struct mnt_id_req __user *, req, if (ret) return ret; + ns = grab_requested_mnt_ns(kreq.mnt_ns_id); + if (!ns) + return -ENOENT; + + if (kreq.mnt_ns_id && (ns != current->nsproxy->mnt_ns) && + !ns_capable_noaudit(ns->user_ns, CAP_SYS_ADMIN)) + return -ENOENT; + retry: ret = prepare_kstatmount(&ks, &kreq, buf, bufsize, seq_size); if (ret) return ret; down_read(&namespace_sem); - mnt = lookup_mnt_in_ns(kreq.mnt_id, current->nsproxy->mnt_ns); + /* Has the namespace already been emptied? */ + if (kreq.mnt_ns_id && RB_EMPTY_ROOT(&ns->mounts)) { + up_read(&namespace_sem); + kvfree(ks.seq.buf); + return -ENOENT; + } + + mnt = lookup_mnt_in_ns(kreq.mnt_id, ns); if (!mnt) { up_read(&namespace_sem); kvfree(ks.seq.buf); @@ -5227,7 +5241,12 @@ SYSCALL_DEFINE4(statmount, const struct mnt_id_req __user *, req, } ks.mnt = mnt; - get_fs_root(current->fs, &ks.root); + ret = grab_requested_root(ns, &ks.root); + if (ret) { + up_read(&namespace_sem); + kvfree(ks.seq.buf); + return ret; + } ret = do_statmount(&ks); path_put(&ks.root); up_read(&namespace_sem); -- 2.43.0