Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * fs/proc_namespace.c - handling of /proc/<pid>/{mounts,mountinfo,mountstats}
0004  *
0005  * In fact, that's a piece of procfs; it's *almost* isolated from
0006  * the rest of fs/proc, but has rather close relationships with
0007  * fs/namespace.c, thus here instead of fs/proc
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     /* mountpoints outside of chroot jail will give SEQ_SKIP on this */
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     /* mountpoints outside of chroot jail will give SEQ_SKIP on this */
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     /* Tagged fields ("foo:X" or "bar") */
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     /* Filesystem specific data */
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     /* device */
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     /* mount point */
0220     seq_puts(m, " mounted on ");
0221     /* mountpoints outside of chroot jail will give SEQ_SKIP on this */
0222     err = seq_path_root(m, &mnt_path, &p->root, " \t\n\\");
0223     if (err)
0224         goto out;
0225     seq_putc(m, ' ');
0226 
0227     /* file system type */
0228     seq_puts(m, "with fstype ");
0229     show_type(m, sb);
0230 
0231     /* optional statistics */
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 };