0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #include <linux/mnt_namespace.h>
0011 #include <linux/nsproxy.h>
0012 #include <linux/security.h>
0013 #include <linux/fs_struct.h>
0014 #include <linux/sched/task.h>
0015
0016 #include "proc/internal.h" /* only for get_proc_task() in ->open() */
0017
0018 #include "pnode.h"
0019 #include "internal.h"
0020
0021 static __poll_t mounts_poll(struct file *file, poll_table *wait)
0022 {
0023 struct seq_file *m = file->private_data;
0024 struct proc_mounts *p = m->private;
0025 struct mnt_namespace *ns = p->ns;
0026 __poll_t res = EPOLLIN | EPOLLRDNORM;
0027 int event;
0028
0029 poll_wait(file, &p->ns->poll, wait);
0030
0031 event = READ_ONCE(ns->event);
0032 if (m->poll_event != event) {
0033 m->poll_event = event;
0034 res |= EPOLLERR | EPOLLPRI;
0035 }
0036
0037 return res;
0038 }
0039
0040 struct proc_fs_opts {
0041 int flag;
0042 const char *str;
0043 };
0044
0045 static int show_sb_opts(struct seq_file *m, struct super_block *sb)
0046 {
0047 static const struct proc_fs_opts fs_opts[] = {
0048 { SB_SYNCHRONOUS, ",sync" },
0049 { SB_DIRSYNC, ",dirsync" },
0050 { SB_MANDLOCK, ",mand" },
0051 { SB_LAZYTIME, ",lazytime" },
0052 { 0, NULL }
0053 };
0054 const struct proc_fs_opts *fs_infop;
0055
0056 for (fs_infop = fs_opts; fs_infop->flag; fs_infop++) {
0057 if (sb->s_flags & fs_infop->flag)
0058 seq_puts(m, fs_infop->str);
0059 }
0060
0061 return security_sb_show_options(m, sb);
0062 }
0063
0064 static void show_mnt_opts(struct seq_file *m, struct vfsmount *mnt)
0065 {
0066 static const struct proc_fs_opts mnt_opts[] = {
0067 { MNT_NOSUID, ",nosuid" },
0068 { MNT_NODEV, ",nodev" },
0069 { MNT_NOEXEC, ",noexec" },
0070 { MNT_NOATIME, ",noatime" },
0071 { MNT_NODIRATIME, ",nodiratime" },
0072 { MNT_RELATIME, ",relatime" },
0073 { MNT_NOSYMFOLLOW, ",nosymfollow" },
0074 { 0, NULL }
0075 };
0076 const struct proc_fs_opts *fs_infop;
0077
0078 for (fs_infop = mnt_opts; fs_infop->flag; fs_infop++) {
0079 if (mnt->mnt_flags & fs_infop->flag)
0080 seq_puts(m, fs_infop->str);
0081 }
0082
0083 if (is_idmapped_mnt(mnt))
0084 seq_puts(m, ",idmapped");
0085 }
0086
0087 static inline void mangle(struct seq_file *m, const char *s)
0088 {
0089 seq_escape(m, s, " \t\n\\#");
0090 }
0091
0092 static void show_type(struct seq_file *m, struct super_block *sb)
0093 {
0094 mangle(m, sb->s_type->name);
0095 if (sb->s_subtype) {
0096 seq_putc(m, '.');
0097 mangle(m, sb->s_subtype);
0098 }
0099 }
0100
0101 static int show_vfsmnt(struct seq_file *m, struct vfsmount *mnt)
0102 {
0103 struct proc_mounts *p = m->private;
0104 struct mount *r = real_mount(mnt);
0105 struct path mnt_path = { .dentry = mnt->mnt_root, .mnt = mnt };
0106 struct super_block *sb = mnt_path.dentry->d_sb;
0107 int err;
0108
0109 if (sb->s_op->show_devname) {
0110 err = sb->s_op->show_devname(m, mnt_path.dentry);
0111 if (err)
0112 goto out;
0113 } else {
0114 mangle(m, r->mnt_devname ? r->mnt_devname : "none");
0115 }
0116 seq_putc(m, ' ');
0117
0118 err = seq_path_root(m, &mnt_path, &p->root, " \t\n\\");
0119 if (err)
0120 goto out;
0121 seq_putc(m, ' ');
0122 show_type(m, sb);
0123 seq_puts(m, __mnt_is_readonly(mnt) ? " ro" : " rw");
0124 err = show_sb_opts(m, sb);
0125 if (err)
0126 goto out;
0127 show_mnt_opts(m, mnt);
0128 if (sb->s_op->show_options)
0129 err = sb->s_op->show_options(m, mnt_path.dentry);
0130 seq_puts(m, " 0 0\n");
0131 out:
0132 return err;
0133 }
0134
0135 static int show_mountinfo(struct seq_file *m, struct vfsmount *mnt)
0136 {
0137 struct proc_mounts *p = m->private;
0138 struct mount *r = real_mount(mnt);
0139 struct super_block *sb = mnt->mnt_sb;
0140 struct path mnt_path = { .dentry = mnt->mnt_root, .mnt = mnt };
0141 int err;
0142
0143 seq_printf(m, "%i %i %u:%u ", r->mnt_id, r->mnt_parent->mnt_id,
0144 MAJOR(sb->s_dev), MINOR(sb->s_dev));
0145 if (sb->s_op->show_path) {
0146 err = sb->s_op->show_path(m, mnt->mnt_root);
0147 if (err)
0148 goto out;
0149 } else {
0150 seq_dentry(m, mnt->mnt_root, " \t\n\\");
0151 }
0152 seq_putc(m, ' ');
0153
0154
0155 err = seq_path_root(m, &mnt_path, &p->root, " \t\n\\");
0156 if (err)
0157 goto out;
0158
0159 seq_puts(m, mnt->mnt_flags & MNT_READONLY ? " ro" : " rw");
0160 show_mnt_opts(m, mnt);
0161
0162
0163 if (IS_MNT_SHARED(r))
0164 seq_printf(m, " shared:%i", r->mnt_group_id);
0165 if (IS_MNT_SLAVE(r)) {
0166 int master = r->mnt_master->mnt_group_id;
0167 int dom = get_dominating_id(r, &p->root);
0168 seq_printf(m, " master:%i", master);
0169 if (dom && dom != master)
0170 seq_printf(m, " propagate_from:%i", dom);
0171 }
0172 if (IS_MNT_UNBINDABLE(r))
0173 seq_puts(m, " unbindable");
0174
0175
0176 seq_puts(m, " - ");
0177 show_type(m, sb);
0178 seq_putc(m, ' ');
0179 if (sb->s_op->show_devname) {
0180 err = sb->s_op->show_devname(m, mnt->mnt_root);
0181 if (err)
0182 goto out;
0183 } else {
0184 mangle(m, r->mnt_devname ? r->mnt_devname : "none");
0185 }
0186 seq_puts(m, sb_rdonly(sb) ? " ro" : " rw");
0187 err = show_sb_opts(m, sb);
0188 if (err)
0189 goto out;
0190 if (sb->s_op->show_options)
0191 err = sb->s_op->show_options(m, mnt->mnt_root);
0192 seq_putc(m, '\n');
0193 out:
0194 return err;
0195 }
0196
0197 static int show_vfsstat(struct seq_file *m, struct vfsmount *mnt)
0198 {
0199 struct proc_mounts *p = m->private;
0200 struct mount *r = real_mount(mnt);
0201 struct path mnt_path = { .dentry = mnt->mnt_root, .mnt = mnt };
0202 struct super_block *sb = mnt_path.dentry->d_sb;
0203 int err;
0204
0205
0206 if (sb->s_op->show_devname) {
0207 seq_puts(m, "device ");
0208 err = sb->s_op->show_devname(m, mnt_path.dentry);
0209 if (err)
0210 goto out;
0211 } else {
0212 if (r->mnt_devname) {
0213 seq_puts(m, "device ");
0214 mangle(m, r->mnt_devname);
0215 } else
0216 seq_puts(m, "no device");
0217 }
0218
0219
0220 seq_puts(m, " mounted on ");
0221
0222 err = seq_path_root(m, &mnt_path, &p->root, " \t\n\\");
0223 if (err)
0224 goto out;
0225 seq_putc(m, ' ');
0226
0227
0228 seq_puts(m, "with fstype ");
0229 show_type(m, sb);
0230
0231
0232 if (sb->s_op->show_stats) {
0233 seq_putc(m, ' ');
0234 err = sb->s_op->show_stats(m, mnt_path.dentry);
0235 }
0236
0237 seq_putc(m, '\n');
0238 out:
0239 return err;
0240 }
0241
0242 static int mounts_open_common(struct inode *inode, struct file *file,
0243 int (*show)(struct seq_file *, struct vfsmount *))
0244 {
0245 struct task_struct *task = get_proc_task(inode);
0246 struct nsproxy *nsp;
0247 struct mnt_namespace *ns = NULL;
0248 struct path root;
0249 struct proc_mounts *p;
0250 struct seq_file *m;
0251 int ret = -EINVAL;
0252
0253 if (!task)
0254 goto err;
0255
0256 task_lock(task);
0257 nsp = task->nsproxy;
0258 if (!nsp || !nsp->mnt_ns) {
0259 task_unlock(task);
0260 put_task_struct(task);
0261 goto err;
0262 }
0263 ns = nsp->mnt_ns;
0264 get_mnt_ns(ns);
0265 if (!task->fs) {
0266 task_unlock(task);
0267 put_task_struct(task);
0268 ret = -ENOENT;
0269 goto err_put_ns;
0270 }
0271 get_fs_root(task->fs, &root);
0272 task_unlock(task);
0273 put_task_struct(task);
0274
0275 ret = seq_open_private(file, &mounts_op, sizeof(struct proc_mounts));
0276 if (ret)
0277 goto err_put_path;
0278
0279 m = file->private_data;
0280 m->poll_event = ns->event;
0281
0282 p = m->private;
0283 p->ns = ns;
0284 p->root = root;
0285 p->show = show;
0286 INIT_LIST_HEAD(&p->cursor.mnt_list);
0287 p->cursor.mnt.mnt_flags = MNT_CURSOR;
0288
0289 return 0;
0290
0291 err_put_path:
0292 path_put(&root);
0293 err_put_ns:
0294 put_mnt_ns(ns);
0295 err:
0296 return ret;
0297 }
0298
0299 static int mounts_release(struct inode *inode, struct file *file)
0300 {
0301 struct seq_file *m = file->private_data;
0302 struct proc_mounts *p = m->private;
0303 path_put(&p->root);
0304 mnt_cursor_del(p->ns, &p->cursor);
0305 put_mnt_ns(p->ns);
0306 return seq_release_private(inode, file);
0307 }
0308
0309 static int mounts_open(struct inode *inode, struct file *file)
0310 {
0311 return mounts_open_common(inode, file, show_vfsmnt);
0312 }
0313
0314 static int mountinfo_open(struct inode *inode, struct file *file)
0315 {
0316 return mounts_open_common(inode, file, show_mountinfo);
0317 }
0318
0319 static int mountstats_open(struct inode *inode, struct file *file)
0320 {
0321 return mounts_open_common(inode, file, show_vfsstat);
0322 }
0323
0324 const struct file_operations proc_mounts_operations = {
0325 .open = mounts_open,
0326 .read_iter = seq_read_iter,
0327 .splice_read = generic_file_splice_read,
0328 .llseek = seq_lseek,
0329 .release = mounts_release,
0330 .poll = mounts_poll,
0331 };
0332
0333 const struct file_operations proc_mountinfo_operations = {
0334 .open = mountinfo_open,
0335 .read_iter = seq_read_iter,
0336 .splice_read = generic_file_splice_read,
0337 .llseek = seq_lseek,
0338 .release = mounts_release,
0339 .poll = mounts_poll,
0340 };
0341
0342 const struct file_operations proc_mountstats_operations = {
0343 .open = mountstats_open,
0344 .read_iter = seq_read_iter,
0345 .splice_read = generic_file_splice_read,
0346 .llseek = seq_lseek,
0347 .release = mounts_release,
0348 };