linux/fs/proc_namespace.c
<<
>>
Prefs
   1/*
   2 * fs/proc_namespace.c - handling of /proc/<pid>/{mounts,mountinfo,mountstats}
   3 *
   4 * In fact, that's a piece of procfs; it's *almost* isolated from
   5 * the rest of fs/proc, but has rather close relationships with
   6 * fs/namespace.c, thus here instead of fs/proc
   7 *
   8 */
   9#include <linux/mnt_namespace.h>
  10#include <linux/nsproxy.h>
  11#include <linux/security.h>
  12#include <linux/fs_struct.h>
  13#include "proc/internal.h" /* only for get_proc_task() in ->open() */
  14
  15#include "pnode.h"
  16#include "internal.h"
  17
  18static unsigned mounts_poll(struct file *file, poll_table *wait)
  19{
  20        struct seq_file *m = file->private_data;
  21        struct proc_mounts *p = m->private;
  22        struct mnt_namespace *ns = p->ns;
  23        unsigned res = POLLIN | POLLRDNORM;
  24        int event;
  25
  26        poll_wait(file, &p->ns->poll, wait);
  27
  28        event = ACCESS_ONCE(ns->event);
  29        if (m->poll_event != event) {
  30                m->poll_event = event;
  31                res |= POLLERR | POLLPRI;
  32        }
  33
  34        return res;
  35}
  36
  37struct proc_fs_info {
  38        int flag;
  39        const char *str;
  40};
  41
  42static int show_sb_opts(struct seq_file *m, struct super_block *sb)
  43{
  44        static const struct proc_fs_info fs_info[] = {
  45                { MS_SYNCHRONOUS, ",sync" },
  46                { MS_DIRSYNC, ",dirsync" },
  47                { MS_MANDLOCK, ",mand" },
  48                { MS_LAZYTIME, ",lazytime" },
  49                { 0, NULL }
  50        };
  51        const struct proc_fs_info *fs_infop;
  52
  53        for (fs_infop = fs_info; fs_infop->flag; fs_infop++) {
  54                if (sb->s_flags & fs_infop->flag)
  55                        seq_puts(m, fs_infop->str);
  56        }
  57
  58        return security_sb_show_options(m, sb);
  59}
  60
  61static void show_mnt_opts(struct seq_file *m, struct vfsmount *mnt)
  62{
  63        static const struct proc_fs_info mnt_info[] = {
  64                { MNT_NOSUID, ",nosuid" },
  65                { MNT_NODEV, ",nodev" },
  66                { MNT_NOEXEC, ",noexec" },
  67                { MNT_NOATIME, ",noatime" },
  68                { MNT_NODIRATIME, ",nodiratime" },
  69                { MNT_RELATIME, ",relatime" },
  70                { 0, NULL }
  71        };
  72        const struct proc_fs_info *fs_infop;
  73
  74        for (fs_infop = mnt_info; fs_infop->flag; fs_infop++) {
  75                if (mnt->mnt_flags & fs_infop->flag)
  76                        seq_puts(m, fs_infop->str);
  77        }
  78}
  79
  80static inline void mangle(struct seq_file *m, const char *s)
  81{
  82        seq_escape(m, s, " \t\n\\");
  83}
  84
  85static void show_type(struct seq_file *m, struct super_block *sb)
  86{
  87        mangle(m, sb->s_type->name);
  88        if (sb->s_subtype && sb->s_subtype[0]) {
  89                seq_putc(m, '.');
  90                mangle(m, sb->s_subtype);
  91        }
  92}
  93
  94static int show_vfsmnt(struct seq_file *m, struct vfsmount *mnt)
  95{
  96        struct proc_mounts *p = m->private;
  97        struct mount *r = real_mount(mnt);
  98        struct path mnt_path = { .dentry = mnt->mnt_root, .mnt = mnt };
  99        struct super_block *sb = mnt_path.dentry->d_sb;
 100        int err;
 101
 102        if (sb->s_op->show_devname) {
 103                err = sb->s_op->show_devname(m, mnt_path.dentry);
 104                if (err)
 105                        goto out;
 106        } else {
 107                mangle(m, r->mnt_devname ? r->mnt_devname : "none");
 108        }
 109        seq_putc(m, ' ');
 110        /* mountpoints outside of chroot jail will give SEQ_SKIP on this */
 111        err = seq_path_root(m, &mnt_path, &p->root, " \t\n\\");
 112        if (err)
 113                goto out;
 114        seq_putc(m, ' ');
 115        show_type(m, sb);
 116        seq_puts(m, __mnt_is_readonly(mnt) ? " ro" : " rw");
 117        err = show_sb_opts(m, sb);
 118        if (err)
 119                goto out;
 120        show_mnt_opts(m, mnt);
 121        if (sb->s_op->show_options)
 122                err = sb->s_op->show_options(m, mnt_path.dentry);
 123        seq_puts(m, " 0 0\n");
 124out:
 125        return err;
 126}
 127
 128static int show_mountinfo(struct seq_file *m, struct vfsmount *mnt)
 129{
 130        struct proc_mounts *p = m->private;
 131        struct mount *r = real_mount(mnt);
 132        struct super_block *sb = mnt->mnt_sb;
 133        struct path mnt_path = { .dentry = mnt->mnt_root, .mnt = mnt };
 134        int err;
 135
 136        seq_printf(m, "%i %i %u:%u ", r->mnt_id, r->mnt_parent->mnt_id,
 137                   MAJOR(sb->s_dev), MINOR(sb->s_dev));
 138        if (sb->s_op->show_path) {
 139                err = sb->s_op->show_path(m, mnt->mnt_root);
 140                if (err)
 141                        goto out;
 142        } else {
 143                seq_dentry(m, mnt->mnt_root, " \t\n\\");
 144        }
 145        seq_putc(m, ' ');
 146
 147        /* mountpoints outside of chroot jail will give SEQ_SKIP on this */
 148        err = seq_path_root(m, &mnt_path, &p->root, " \t\n\\");
 149        if (err)
 150                goto out;
 151
 152        seq_puts(m, mnt->mnt_flags & MNT_READONLY ? " ro" : " rw");
 153        show_mnt_opts(m, mnt);
 154
 155        /* Tagged fields ("foo:X" or "bar") */
 156        if (IS_MNT_SHARED(r))
 157                seq_printf(m, " shared:%i", r->mnt_group_id);
 158        if (IS_MNT_SLAVE(r)) {
 159                int master = r->mnt_master->mnt_group_id;
 160                int dom = get_dominating_id(r, &p->root);
 161                seq_printf(m, " master:%i", master);
 162                if (dom && dom != master)
 163                        seq_printf(m, " propagate_from:%i", dom);
 164        }
 165        if (IS_MNT_UNBINDABLE(r))
 166                seq_puts(m, " unbindable");
 167
 168        /* Filesystem specific data */
 169        seq_puts(m, " - ");
 170        show_type(m, sb);
 171        seq_putc(m, ' ');
 172        if (sb->s_op->show_devname) {
 173                err = sb->s_op->show_devname(m, mnt->mnt_root);
 174                if (err)
 175                        goto out;
 176        } else {
 177                mangle(m, r->mnt_devname ? r->mnt_devname : "none");
 178        }
 179        seq_puts(m, sb->s_flags & MS_RDONLY ? " ro" : " rw");
 180        err = show_sb_opts(m, sb);
 181        if (err)
 182                goto out;
 183        if (sb->s_op->show_options)
 184                err = sb->s_op->show_options(m, mnt->mnt_root);
 185        seq_putc(m, '\n');
 186out:
 187        return err;
 188}
 189
 190static int show_vfsstat(struct seq_file *m, struct vfsmount *mnt)
 191{
 192        struct proc_mounts *p = m->private;
 193        struct mount *r = real_mount(mnt);
 194        struct path mnt_path = { .dentry = mnt->mnt_root, .mnt = mnt };
 195        struct super_block *sb = mnt_path.dentry->d_sb;
 196        int err;
 197
 198        /* device */
 199        if (sb->s_op->show_devname) {
 200                seq_puts(m, "device ");
 201                err = sb->s_op->show_devname(m, mnt_path.dentry);
 202                if (err)
 203                        goto out;
 204        } else {
 205                if (r->mnt_devname) {
 206                        seq_puts(m, "device ");
 207                        mangle(m, r->mnt_devname);
 208                } else
 209                        seq_puts(m, "no device");
 210        }
 211
 212        /* mount point */
 213        seq_puts(m, " mounted on ");
 214        /* mountpoints outside of chroot jail will give SEQ_SKIP on this */
 215        err = seq_path_root(m, &mnt_path, &p->root, " \t\n\\");
 216        if (err)
 217                goto out;
 218        seq_putc(m, ' ');
 219
 220        /* file system type */
 221        seq_puts(m, "with fstype ");
 222        show_type(m, sb);
 223
 224        /* optional statistics */
 225        if (sb->s_op->show_stats) {
 226                seq_putc(m, ' ');
 227                err = sb->s_op->show_stats(m, mnt_path.dentry);
 228        }
 229
 230        seq_putc(m, '\n');
 231out:
 232        return err;
 233}
 234
 235static int mounts_open_common(struct inode *inode, struct file *file,
 236                              int (*show)(struct seq_file *, struct vfsmount *))
 237{
 238        struct task_struct *task = get_proc_task(inode);
 239        struct nsproxy *nsp;
 240        struct mnt_namespace *ns = NULL;
 241        struct path root;
 242        struct proc_mounts *p;
 243        struct seq_file *m;
 244        int ret = -EINVAL;
 245
 246        if (!task)
 247                goto err;
 248
 249        task_lock(task);
 250        nsp = task->nsproxy;
 251        if (!nsp || !nsp->mnt_ns) {
 252                task_unlock(task);
 253                put_task_struct(task);
 254                goto err;
 255        }
 256        ns = nsp->mnt_ns;
 257        get_mnt_ns(ns);
 258        if (!task->fs) {
 259                task_unlock(task);
 260                put_task_struct(task);
 261                ret = -ENOENT;
 262                goto err_put_ns;
 263        }
 264        get_fs_root(task->fs, &root);
 265        task_unlock(task);
 266        put_task_struct(task);
 267
 268        ret = seq_open_private(file, &mounts_op, sizeof(struct proc_mounts));
 269        if (ret)
 270                goto err_put_path;
 271
 272        m = file->private_data;
 273        m->poll_event = ns->event;
 274
 275        p = m->private;
 276        p->ns = ns;
 277        p->root = root;
 278        p->show = show;
 279        p->cached_event = ~0ULL;
 280
 281        return 0;
 282
 283 err_put_path:
 284        path_put(&root);
 285 err_put_ns:
 286        put_mnt_ns(ns);
 287 err:
 288        return ret;
 289}
 290
 291static int mounts_release(struct inode *inode, struct file *file)
 292{
 293        struct seq_file *m = file->private_data;
 294        struct proc_mounts *p = m->private;
 295        path_put(&p->root);
 296        put_mnt_ns(p->ns);
 297        return seq_release_private(inode, file);
 298}
 299
 300static int mounts_open(struct inode *inode, struct file *file)
 301{
 302        return mounts_open_common(inode, file, show_vfsmnt);
 303}
 304
 305static int mountinfo_open(struct inode *inode, struct file *file)
 306{
 307        return mounts_open_common(inode, file, show_mountinfo);
 308}
 309
 310static int mountstats_open(struct inode *inode, struct file *file)
 311{
 312        return mounts_open_common(inode, file, show_vfsstat);
 313}
 314
 315const struct file_operations proc_mounts_operations = {
 316        .open           = mounts_open,
 317        .read           = seq_read,
 318        .llseek         = seq_lseek,
 319        .release        = mounts_release,
 320        .poll           = mounts_poll,
 321};
 322
 323const struct file_operations proc_mountinfo_operations = {
 324        .open           = mountinfo_open,
 325        .read           = seq_read,
 326        .llseek         = seq_lseek,
 327        .release        = mounts_release,
 328        .poll           = mounts_poll,
 329};
 330
 331const struct file_operations proc_mountstats_operations = {
 332        .open           = mountstats_open,
 333        .read           = seq_read,
 334        .llseek         = seq_lseek,
 335        .release        = mounts_release,
 336};
 337