| @@ -32,6 +32,7 @@ · 31 unmodified lines |
| 32 | 32 | #include <linux/fs_context.h> |
| 33 | 33 | #include <linux/shmem_fs.h> |
| 34 | 34 | #include <linux/mnt_idmapping.h> |
| 35 | +#include <linux/nospec.h> |
| 35 | 36 | |
| 36 | 37 | #include "pnode.h" |
| 37 | 38 | #include "internal.h" |
| @@ -1009,7 +1010,7 @@ void mnt_change_mountpoint(struct mount *parent, struct mountpoint *mp, struct m · 971 unmodified lines |
| 1009 | 1010 | |
| 1010 | 1011 | static inline struct mount *node_to_mount(struct rb_node *node) |
| 1011 | 1012 | { |
| 1012 | | − return rb_entry(node, struct mount, mnt_node); |
| 1013 | + return node ? rb_entry(node, struct mount, mnt_node) : NULL; |
| 1013 | 1014 | } |
| 1014 | 1015 | |
| 1015 | 1016 | static void mnt_add_to_ns(struct mnt_namespace *ns, struct mount *mnt) |
| @@ -4945,7 +4946,7 @@ static int prepare_kstatmount(struct kstatmount *ks, struct mnt_id_req *kreq, · 3929 unmodified lines |
| 4945 | 4946 | return -EFAULT; |
| 4946 | 4947 | |
| 4947 | 4948 | memset(ks, 0, sizeof(*ks)); |
| 4948 | | − ks->mask = kreq->request_mask; |
| 4949 | + ks->mask = kreq->param; |
| 4949 | 4950 | ks->buf = buf; |
| 4950 | 4951 | ks->bufsize = bufsize; |
| 4951 | 4952 | ks->seq.size = seq_size; |
| @@ -4999,6 +5000,87 @@ retry: · 47 unmodified lines |
| 4999 | 5000 | return ret; |
| 5000 | 5001 | } |
| 5001 | 5002 | |
| 5003 | +static struct mount *listmnt_next(struct mount *curr) |
| 5004 | +{ |
| 5005 | + return node_to_mount(rb_next(&curr->mnt_node)); |
| 5006 | +} |
| 5007 | + |
| 5008 | +static ssize_t do_listmount(struct mount *first, struct path *orig, u64 mnt_id, |
| 5009 | + u64 __user *buf, size_t bufsize, |
| 5010 | + const struct path *root) |
| 5011 | +{ |
| 5012 | + struct mount *r; |
| 5013 | + ssize_t ctr; |
| 5014 | + int err; |
| 5015 | + |
| 5016 | + /* |
| 5017 | + * Don't trigger audit denials. We just want to determine what |
| 5018 | + * mounts to show users. |
| 5019 | + */ |
| 5020 | + if (!is_path_reachable(real_mount(orig->mnt), orig->dentry, root) && |
| 5021 | + !ns_capable_noaudit(&init_user_ns, CAP_SYS_ADMIN)) |
| 5022 | + return -EPERM; |
| 5023 | + |
| 5024 | + err = security_sb_statfs(orig->dentry); |
| 5025 | + if (err) |
| 5026 | + return err; |
| 5027 | + |
| 5028 | + for (ctr = 0, r = first; r && ctr < bufsize; r = listmnt_next(r)) { |
| 5029 | + if (r->mnt_id_unique == mnt_id) |
| 5030 | + continue; |
| 5031 | + if (!is_path_reachable(r, r->mnt.mnt_root, orig)) |
| 5032 | + continue; |
| 5033 | + ctr = array_index_nospec(ctr, bufsize); |
| 5034 | + if (put_user(r->mnt_id_unique, buf + ctr)) |
| 5035 | + return -EFAULT; |
| 5036 | + if (check_add_overflow(ctr, 1, &ctr)) |
| 5037 | + return -ERANGE; |
| 5038 | + } |
| 5039 | + return ctr; |
| 5040 | +} |
| 5041 | + |
| 5042 | +SYSCALL_DEFINE4(listmount, const struct mnt_id_req __user *, req, |
| 5043 | + u64 __user *, buf, size_t, bufsize, unsigned int, flags) |
| 5044 | +{ |
| 5045 | + struct mnt_namespace *ns = current->nsproxy->mnt_ns; |
| 5046 | + struct mnt_id_req kreq; |
| 5047 | + struct mount *first; |
| 5048 | + struct path root, orig; |
| 5049 | + u64 mnt_id, last_mnt_id; |
| 5050 | + ssize_t ret; |
| 5051 | + |
| 5052 | + if (flags) |
| 5053 | + return -EINVAL; |
| 5054 | + |
| 5055 | + if (copy_from_user(&kreq, req, sizeof(kreq))) |
| 5056 | + return -EFAULT; |
| 5057 | + mnt_id = kreq.mnt_id; |
| 5058 | + last_mnt_id = kreq.param; |
| 5059 | + |
| 5060 | + down_read(&namespace_sem); |
| 5061 | + get_fs_root(current->fs, &root); |
| 5062 | + if (mnt_id == LSMT_ROOT) { |
| 5063 | + orig = root; |
| 5064 | + } else { |
| 5065 | + ret = -ENOENT; |
| 5066 | + orig.mnt = lookup_mnt_in_ns(mnt_id, ns); |
| 5067 | + if (!orig.mnt) |
| 5068 | + goto err; |
| 5069 | + orig.dentry = orig.mnt->mnt_root; |
| 5070 | + } |
| 5071 | + if (!last_mnt_id) |
| 5072 | + first = node_to_mount(rb_first(&ns->mounts)); |
| 5073 | + else |
| 5074 | + first = mnt_find_id_at(ns, last_mnt_id + 1); |
| 5075 | + |
| 5076 | + ret = do_listmount(first, &orig, mnt_id, buf, bufsize, &root); |
| 5077 | +err: |
| 5078 | + path_put(&root); |
| 5079 | + up_read(&namespace_sem); |
| 5080 | + return ret; |
| 5081 | +} |
| 5082 | + |
| 5083 | + |
| 5002 | 5084 | static void __init init_mount_tree(void) |
| 5003 | 5085 | { |
| 5004 | 5086 | struct vfsmount *mnt; |