Back to home page

LXR

 
 

    


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