LCOV - code coverage report
Current view: top level - fs - proc_namespace.c (source / functions) Hit Total Coverage
Test: fstests of 6.5.0-rc4-xfsa @ Mon Jul 31 20:08:27 PDT 2023 Lines: 141 191 73.8 %
Date: 2023-07-31 20:08:27 Functions: 10 12 83.3 %

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

Generated by: LCOV version 1.14