Loading fs/namespace.c +83 −77 Original line number Diff line number Diff line Loading @@ -5040,17 +5040,70 @@ static int copy_statmount_to_user(struct kstatmount *s) return 0; } static int do_statmount(struct kstatmount *s) static struct mount *listmnt_next(struct mount *curr, bool reverse) { struct mount *m = real_mount(s->mnt); struct mnt_namespace *ns = m->mnt_ns; struct rb_node *node; if (reverse) node = rb_prev(&curr->mnt_node); else node = rb_next(&curr->mnt_node); return node_to_mount(node); } static int grab_requested_root(struct mnt_namespace *ns, struct path *root) { struct mount *first; rwsem_assert_held(&namespace_sem); /* We're looking at our own ns, just use get_fs_root. */ if (ns == current->nsproxy->mnt_ns) { get_fs_root(current->fs, root); return 0; } /* * We have to find the first mount in our ns and use that, however it * may not exist, so handle that properly. */ if (RB_EMPTY_ROOT(&ns->mounts)) return -ENOENT; first = listmnt_next(ns->root, false); if (!first) return -ENOENT; root->mnt = mntget(&first->mnt); root->dentry = dget(root->mnt->mnt_root); return 0; } static int do_statmount(struct kstatmount *s, u64 mnt_id, u64 mnt_ns_id, struct mnt_namespace *ns) { struct path root __free(path_put) = {}; struct mount *m; int err; /* Has the namespace already been emptied? */ if (mnt_ns_id && RB_EMPTY_ROOT(&ns->mounts)) return -ENOENT; s->mnt = lookup_mnt_in_ns(mnt_id, ns); if (!s->mnt) return -ENOENT; err = grab_requested_root(ns, &root); if (err) return err; /* * Don't trigger audit denials. We just want to determine what * mounts to show users. */ if (!is_path_reachable(m, m->mnt.mnt_root, &s->root) && m = real_mount(s->mnt); if (!is_path_reachable(m, m->mnt.mnt_root, &root) && !ns_capable_noaudit(ns->user_ns, CAP_SYS_ADMIN)) return -EPERM; Loading @@ -5058,6 +5111,7 @@ static int do_statmount(struct kstatmount *s) if (err) return err; s->root = root; if (s->mask & STATMOUNT_SB_BASIC) statmount_sb_basic(s); Loading Loading @@ -5096,6 +5150,9 @@ static inline bool retry_statmount(const long ret, size_t *seq_size) return true; } #define STATMOUNT_STRING_REQ (STATMOUNT_MNT_ROOT | STATMOUNT_MNT_POINT | \ STATMOUNT_FS_TYPE) static int prepare_kstatmount(struct kstatmount *ks, struct mnt_id_req *kreq, struct statmount __user *buf, size_t bufsize, size_t seq_size) Loading @@ -5107,10 +5164,18 @@ static int prepare_kstatmount(struct kstatmount *ks, struct mnt_id_req *kreq, ks->mask = kreq->param; ks->buf = buf; ks->bufsize = bufsize; ks->seq.size = seq_size; if (ks->mask & STATMOUNT_STRING_REQ) { if (bufsize == sizeof(ks->sm)) return -EOVERFLOW; ks->seq.buf = kvmalloc(seq_size, GFP_KERNEL_ACCOUNT); if (!ks->seq.buf) return -ENOMEM; ks->seq.size = seq_size; } return 0; } Loading Loading @@ -5138,45 +5203,6 @@ static int copy_mnt_id_req(const struct mnt_id_req __user *req, return 0; } static struct mount *listmnt_next(struct mount *curr, bool reverse) { struct rb_node *node; if (reverse) node = rb_prev(&curr->mnt_node); else node = rb_next(&curr->mnt_node); return node_to_mount(node); } static int grab_requested_root(struct mnt_namespace *ns, struct path *root) { struct mount *first; rwsem_assert_held(&namespace_sem); /* We're looking at our own ns, just use get_fs_root. */ if (ns == current->nsproxy->mnt_ns) { get_fs_root(current->fs, root); return 0; } /* * We have to find the first mount in our ns and use that, however it * may not exist, so handle that properly. */ if (RB_EMPTY_ROOT(&ns->mounts)) return -ENOENT; first = listmnt_next(ns->root, false); if (!first) return -ENOENT; root->mnt = mntget(&first->mnt); root->dentry = dget(root->mnt->mnt_root); return 0; } /* * If the user requested a specific mount namespace id, look that up and return * that, or if not simply grab a passive reference on our mount namespace and Loading @@ -5195,9 +5221,8 @@ SYSCALL_DEFINE4(statmount, const struct mnt_id_req __user *, req, unsigned int, flags) { struct mnt_namespace *ns __free(mnt_ns_release) = NULL; struct vfsmount *mnt; struct kstatmount *ks __free(kfree) = NULL; struct mnt_id_req kreq; struct kstatmount ks; /* We currently support retrieval of 3 strings. */ size_t seq_size = 3 * PATH_MAX; int ret; Loading @@ -5217,40 +5242,21 @@ SYSCALL_DEFINE4(statmount, const struct mnt_id_req __user *, req, !ns_capable_noaudit(ns->user_ns, CAP_SYS_ADMIN)) return -ENOENT; ks = kmalloc(sizeof(*ks), GFP_KERNEL_ACCOUNT); if (!ks) return -ENOMEM; retry: ret = prepare_kstatmount(&ks, &kreq, buf, bufsize, seq_size); ret = prepare_kstatmount(ks, &kreq, buf, bufsize, seq_size); if (ret) return ret; down_read(&namespace_sem); /* 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); return -ENOENT; } ks.mnt = mnt; 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); scoped_guard(rwsem_read, &namespace_sem) ret = do_statmount(ks, kreq.mnt_id, kreq.mnt_ns_id, ns); if (!ret) ret = copy_statmount_to_user(&ks); kvfree(ks.seq.buf); ret = copy_statmount_to_user(ks); kvfree(ks->seq.buf); if (retry_statmount(ret, &seq_size)) goto retry; return ret; Loading Loading
fs/namespace.c +83 −77 Original line number Diff line number Diff line Loading @@ -5040,17 +5040,70 @@ static int copy_statmount_to_user(struct kstatmount *s) return 0; } static int do_statmount(struct kstatmount *s) static struct mount *listmnt_next(struct mount *curr, bool reverse) { struct mount *m = real_mount(s->mnt); struct mnt_namespace *ns = m->mnt_ns; struct rb_node *node; if (reverse) node = rb_prev(&curr->mnt_node); else node = rb_next(&curr->mnt_node); return node_to_mount(node); } static int grab_requested_root(struct mnt_namespace *ns, struct path *root) { struct mount *first; rwsem_assert_held(&namespace_sem); /* We're looking at our own ns, just use get_fs_root. */ if (ns == current->nsproxy->mnt_ns) { get_fs_root(current->fs, root); return 0; } /* * We have to find the first mount in our ns and use that, however it * may not exist, so handle that properly. */ if (RB_EMPTY_ROOT(&ns->mounts)) return -ENOENT; first = listmnt_next(ns->root, false); if (!first) return -ENOENT; root->mnt = mntget(&first->mnt); root->dentry = dget(root->mnt->mnt_root); return 0; } static int do_statmount(struct kstatmount *s, u64 mnt_id, u64 mnt_ns_id, struct mnt_namespace *ns) { struct path root __free(path_put) = {}; struct mount *m; int err; /* Has the namespace already been emptied? */ if (mnt_ns_id && RB_EMPTY_ROOT(&ns->mounts)) return -ENOENT; s->mnt = lookup_mnt_in_ns(mnt_id, ns); if (!s->mnt) return -ENOENT; err = grab_requested_root(ns, &root); if (err) return err; /* * Don't trigger audit denials. We just want to determine what * mounts to show users. */ if (!is_path_reachable(m, m->mnt.mnt_root, &s->root) && m = real_mount(s->mnt); if (!is_path_reachable(m, m->mnt.mnt_root, &root) && !ns_capable_noaudit(ns->user_ns, CAP_SYS_ADMIN)) return -EPERM; Loading @@ -5058,6 +5111,7 @@ static int do_statmount(struct kstatmount *s) if (err) return err; s->root = root; if (s->mask & STATMOUNT_SB_BASIC) statmount_sb_basic(s); Loading Loading @@ -5096,6 +5150,9 @@ static inline bool retry_statmount(const long ret, size_t *seq_size) return true; } #define STATMOUNT_STRING_REQ (STATMOUNT_MNT_ROOT | STATMOUNT_MNT_POINT | \ STATMOUNT_FS_TYPE) static int prepare_kstatmount(struct kstatmount *ks, struct mnt_id_req *kreq, struct statmount __user *buf, size_t bufsize, size_t seq_size) Loading @@ -5107,10 +5164,18 @@ static int prepare_kstatmount(struct kstatmount *ks, struct mnt_id_req *kreq, ks->mask = kreq->param; ks->buf = buf; ks->bufsize = bufsize; ks->seq.size = seq_size; if (ks->mask & STATMOUNT_STRING_REQ) { if (bufsize == sizeof(ks->sm)) return -EOVERFLOW; ks->seq.buf = kvmalloc(seq_size, GFP_KERNEL_ACCOUNT); if (!ks->seq.buf) return -ENOMEM; ks->seq.size = seq_size; } return 0; } Loading Loading @@ -5138,45 +5203,6 @@ static int copy_mnt_id_req(const struct mnt_id_req __user *req, return 0; } static struct mount *listmnt_next(struct mount *curr, bool reverse) { struct rb_node *node; if (reverse) node = rb_prev(&curr->mnt_node); else node = rb_next(&curr->mnt_node); return node_to_mount(node); } static int grab_requested_root(struct mnt_namespace *ns, struct path *root) { struct mount *first; rwsem_assert_held(&namespace_sem); /* We're looking at our own ns, just use get_fs_root. */ if (ns == current->nsproxy->mnt_ns) { get_fs_root(current->fs, root); return 0; } /* * We have to find the first mount in our ns and use that, however it * may not exist, so handle that properly. */ if (RB_EMPTY_ROOT(&ns->mounts)) return -ENOENT; first = listmnt_next(ns->root, false); if (!first) return -ENOENT; root->mnt = mntget(&first->mnt); root->dentry = dget(root->mnt->mnt_root); return 0; } /* * If the user requested a specific mount namespace id, look that up and return * that, or if not simply grab a passive reference on our mount namespace and Loading @@ -5195,9 +5221,8 @@ SYSCALL_DEFINE4(statmount, const struct mnt_id_req __user *, req, unsigned int, flags) { struct mnt_namespace *ns __free(mnt_ns_release) = NULL; struct vfsmount *mnt; struct kstatmount *ks __free(kfree) = NULL; struct mnt_id_req kreq; struct kstatmount ks; /* We currently support retrieval of 3 strings. */ size_t seq_size = 3 * PATH_MAX; int ret; Loading @@ -5217,40 +5242,21 @@ SYSCALL_DEFINE4(statmount, const struct mnt_id_req __user *, req, !ns_capable_noaudit(ns->user_ns, CAP_SYS_ADMIN)) return -ENOENT; ks = kmalloc(sizeof(*ks), GFP_KERNEL_ACCOUNT); if (!ks) return -ENOMEM; retry: ret = prepare_kstatmount(&ks, &kreq, buf, bufsize, seq_size); ret = prepare_kstatmount(ks, &kreq, buf, bufsize, seq_size); if (ret) return ret; down_read(&namespace_sem); /* 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); return -ENOENT; } ks.mnt = mnt; 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); scoped_guard(rwsem_read, &namespace_sem) ret = do_statmount(ks, kreq.mnt_id, kreq.mnt_ns_id, ns); if (!ret) ret = copy_statmount_to_user(&ks); kvfree(ks.seq.buf); ret = copy_statmount_to_user(ks); kvfree(ks->seq.buf); if (retry_statmount(ret, &seq_size)) goto retry; return ret; Loading