LCOV - code coverage report
Current view: top level - fs - proc_namespace.c (source / functions) Hit Total Coverage
Test: fstests of 6.5.0-rc3-acha @ Mon Jul 31 20:08:06 PDT 2023 Lines: 141 191 73.8 %
Date: 2023-07-31 20:08:07 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      190089 : static __poll_t mounts_poll(struct file *file, poll_table *wait)
      22             : {
      23      190089 :         struct seq_file *m = file->private_data;
      24      190089 :         struct proc_mounts *p = m->private;
      25      190089 :         struct mnt_namespace *ns = p->ns;
      26      190089 :         __poll_t res = EPOLLIN | EPOLLRDNORM;
      27      190089 :         int event;
      28             : 
      29      190089 :         poll_wait(file, &p->ns->poll, wait);
      30             : 
      31      192644 :         event = READ_ONCE(ns->event);
      32      192644 :         if (m->poll_event != event) {
      33       97325 :                 m->poll_event = event;
      34       97325 :                 res |= EPOLLERR | EPOLLPRI;
      35             :         }
      36             : 
      37      192644 :         return res;
      38             : }
      39             : 
      40             : struct proc_fs_opts {
      41             :         int flag;
      42             :         const char *str;
      43             : };
      44             : 
      45   264430784 : static int show_sb_opts(struct seq_file *m, struct super_block *sb)
      46             : {
      47   264430784 :         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   264430784 :         const struct proc_fs_opts *fs_infop;
      55             : 
      56  1322049462 :         for (fs_infop = fs_opts; fs_infop->flag; fs_infop++) {
      57  1057342876 :                 if (sb->s_flags & fs_infop->flag)
      58        1229 :                         seq_puts(m, fs_infop->str);
      59             :         }
      60             : 
      61   264706586 :         return security_sb_show_options(m, sb);
      62             : }
      63             : 
      64   264604043 : static void show_mnt_opts(struct seq_file *m, struct vfsmount *mnt)
      65             : {
      66   264604043 :         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   264604043 :         const struct proc_fs_opts *fs_infop;
      77             : 
      78  2115648441 :         for (fs_infop = mnt_opts; fs_infop->flag; fs_infop++) {
      79  1850538093 :                 if (mnt->mnt_flags & fs_infop->flag)
      80   428817869 :                         seq_puts(m, fs_infop->str);
      81             :         }
      82             : 
      83   265110348 :         if (is_idmapped_mnt(mnt))
      84         378 :                 seq_puts(m, ",idmapped");
      85   264712949 : }
      86             : 
      87             : static inline void mangle(struct seq_file *m, const char *s)
      88             : {
      89   243380564 :         seq_escape(m, s, " \t\n\\#");
      90   243552106 : }
      91             : 
      92   264892943 : static void show_type(struct seq_file *m, struct super_block *sb)
      93             : {
      94   264892943 :         mangle(m, sb->s_type->name);
      95   263636082 :         if (sb->s_subtype) {
      96           0 :                 seq_putc(m, '.');
      97           0 :                 mangle(m, sb->s_subtype);
      98             :         }
      99   263636082 : }
     100             : 
     101   247250649 : static int show_vfsmnt(struct seq_file *m, struct vfsmount *mnt)
     102             : {
     103   247250649 :         struct proc_mounts *p = m->private;
     104   247250649 :         struct mount *r = real_mount(mnt);
     105   247250649 :         struct path mnt_path = { .dentry = mnt->mnt_root, .mnt = mnt };
     106   247250649 :         struct super_block *sb = mnt_path.dentry->d_sb;
     107   247250649 :         int err;
     108             : 
     109   247250649 :         if (sb->s_op->show_devname) {
     110    21098790 :                 err = sb->s_op->show_devname(m, mnt_path.dentry);
     111    21114999 :                 if (err)
     112           0 :                         goto out;
     113             :         } else {
     114   226151859 :                 mangle(m, r->mnt_devname ? r->mnt_devname : "none");
     115             :         }
     116   247460928 :         seq_putc(m, ' ');
     117             :         /* mountpoints outside of chroot jail will give SEQ_SKIP on this */
     118   247447064 :         err = seq_path_root(m, &mnt_path, &p->root, " \t\n\\");
     119   248565325 :         if (err)
     120     2596469 :                 goto out;
     121   245968856 :         seq_putc(m, ' ');
     122   245984546 :         show_type(m, sb);
     123   349732890 :         seq_puts(m, __mnt_is_readonly(mnt) ? " ro" : " rw");
     124   245574524 :         err = show_sb_opts(m, sb);
     125   245648032 :         if (err)
     126           0 :                 goto out;
     127   245648032 :         show_mnt_opts(m, mnt);
     128   245590176 :         if (sb->s_op->show_options)
     129   229890515 :                 err = sb->s_op->show_options(m, mnt_path.dentry);
     130   244903519 :         seq_puts(m, " 0 0\n");
     131   247578734 : out:
     132   247578734 :         return err;
     133             : }
     134             : 
     135    19153477 : static int show_mountinfo(struct seq_file *m, struct vfsmount *mnt)
     136             : {
     137    19153477 :         struct proc_mounts *p = m->private;
     138    19153477 :         struct mount *r = real_mount(mnt);
     139    19153477 :         struct super_block *sb = mnt->mnt_sb;
     140    19153477 :         struct path mnt_path = { .dentry = mnt->mnt_root, .mnt = mnt };
     141    19153477 :         int err;
     142             : 
     143    19153477 :         seq_printf(m, "%i %i %u:%u ", r->mnt_id, r->mnt_parent->mnt_id,
     144    19153477 :                    MAJOR(sb->s_dev), MINOR(sb->s_dev));
     145    19121147 :         if (sb->s_op->show_path) {
     146     2037439 :                 err = sb->s_op->show_path(m, mnt->mnt_root);
     147     2037104 :                 if (err)
     148           0 :                         goto out;
     149             :         } else {
     150    17083708 :                 seq_dentry(m, mnt->mnt_root, " \t\n\\");
     151             :         }
     152    19202371 :         seq_putc(m, ' ');
     153             : 
     154             :         /* mountpoints outside of chroot jail will give SEQ_SKIP on this */
     155    19204580 :         err = seq_path_root(m, &mnt_path, &p->root, " \t\n\\");
     156    19229809 :         if (err)
     157      200779 :                 goto out;
     158             : 
     159    27160757 :         seq_puts(m, mnt->mnt_flags & MNT_READONLY ? " ro" : " rw");
     160    19043235 :         show_mnt_opts(m, mnt);
     161             : 
     162             :         /* Tagged fields ("foo:X" or "bar") */
     163    19030705 :         if (IS_MNT_SHARED(r))
     164    18683401 :                 seq_printf(m, " shared:%i", r->mnt_group_id);
     165    19031510 :         if (IS_MNT_SLAVE(r)) {
     166      352693 :                 int master = r->mnt_master->mnt_group_id;
     167      352693 :                 int dom = get_dominating_id(r, &p->root);
     168      352693 :                 seq_printf(m, " master:%i", master);
     169      352690 :                 if (dom && dom != master)
     170           0 :                         seq_printf(m, " propagate_from:%i", dom);
     171             :         }
     172    19031507 :         if (IS_MNT_UNBINDABLE(r))
     173          47 :                 seq_puts(m, " unbindable");
     174             : 
     175             :         /* Filesystem specific data */
     176    19031507 :         seq_puts(m, " - ");
     177    19029509 :         show_type(m, sb);
     178    18858612 :         seq_putc(m, ' ');
     179    18850957 :         if (sb->s_op->show_devname) {
     180     1622252 :                 err = sb->s_op->show_devname(m, mnt->mnt_root);
     181     1635349 :                 if (err)
     182           0 :                         goto out;
     183             :         } else {
     184    17228705 :                 mangle(m, r->mnt_devname ? r->mnt_devname : "none");
     185             :         }
     186    37651906 :         seq_puts(m, sb_rdonly(sb) ? " ro" : " rw");
     187    18816367 :         err = show_sb_opts(m, sb);
     188    18819065 :         if (err)
     189           0 :                 goto out;
     190    18819065 :         if (sb->s_op->show_options)
     191    17599782 :                 err = sb->s_op->show_options(m, mnt->mnt_root);
     192    18763377 :         seq_putc(m, '\n');
     193    18952113 : out:
     194    18952113 :         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     2840364 : static int mounts_open_common(struct inode *inode, struct file *file,
     243             :                               int (*show)(struct seq_file *, struct vfsmount *))
     244             : {
     245     2840364 :         struct task_struct *task = get_proc_task(inode);
     246     2824067 :         struct nsproxy *nsp;
     247     2824067 :         struct mnt_namespace *ns = NULL;
     248     2824067 :         struct path root;
     249     2824067 :         struct proc_mounts *p;
     250     2824067 :         struct seq_file *m;
     251     2824067 :         int ret = -EINVAL;
     252             : 
     253     2824067 :         if (!task)
     254           0 :                 goto err;
     255             : 
     256     2824067 :         task_lock(task);
     257     2825980 :         nsp = task->nsproxy;
     258     2825980 :         if (!nsp || !nsp->mnt_ns) {
     259           0 :                 task_unlock(task);
     260           0 :                 put_task_struct(task);
     261           0 :                 goto err;
     262             :         }
     263     2825980 :         ns = nsp->mnt_ns;
     264     2825980 :         get_mnt_ns(ns);
     265     2808162 :         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     2808162 :         get_fs_root(task->fs, &root);
     272     2843879 :         task_unlock(task);
     273     2813073 :         put_task_struct(task);
     274             : 
     275     2806565 :         ret = seq_open_private(file, &mounts_op, sizeof(struct proc_mounts));
     276     2820338 :         if (ret)
     277           0 :                 goto err_put_path;
     278             : 
     279     2820338 :         m = file->private_data;
     280     2820338 :         m->poll_event = ns->event;
     281             : 
     282     2820338 :         p = m->private;
     283     2820338 :         p->ns = ns;
     284     2820338 :         p->root = root;
     285     2820338 :         p->show = show;
     286     2820338 :         INIT_LIST_HEAD(&p->cursor.mnt_list);
     287     2820338 :         p->cursor.mnt.mnt_flags = MNT_CURSOR;
     288             : 
     289     2820338 :         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     2834841 : static int mounts_release(struct inode *inode, struct file *file)
     300             : {
     301     2834841 :         struct seq_file *m = file->private_data;
     302     2834841 :         struct proc_mounts *p = m->private;
     303     2834841 :         path_put(&p->root);
     304     2839741 :         mnt_cursor_del(p->ns, &p->cursor);
     305     2841669 :         put_mnt_ns(p->ns);
     306     2817292 :         return seq_release_private(inode, file);
     307             : }
     308             : 
     309     2615397 : static int mounts_open(struct inode *inode, struct file *file)
     310             : {
     311     2615397 :         return mounts_open_common(inode, file, show_vfsmnt);
     312             : }
     313             : 
     314      198971 : static int mountinfo_open(struct inode *inode, struct file *file)
     315             : {
     316      198971 :         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