|
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
|
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,
|
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 @@ SYSCALL_DEFINE4(statmount, const struct mnt_id_req __user *, req,
|
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;
|
|
0 commit comments