LCOV - code coverage report
Current view: top level - fs - proc_namespace.c (source / functions) Hit Total Coverage
Test: fstests of 6.5.0-rc3-djwx @ Mon Jul 31 20:08:22 PDT 2023 Lines: 141 191 73.8 %
Date: 2023-07-31 20:08:22 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      527586 : static __poll_t mounts_poll(struct file *file, poll_table *wait)
      22             : {
      23      527586 :         struct seq_file *m = file->private_data;
      24      527586 :         struct proc_mounts *p = m->private;
      25      527586 :         struct mnt_namespace *ns = p->ns;
      26      527586 :         __poll_t res = EPOLLIN | EPOLLRDNORM;
      27      527586 :         int event;
      28             : 
      29      527586 :         poll_wait(file, &p->ns->poll, wait);
      30             : 
      31      528338 :         event = READ_ONCE(ns->event);
      32      528338 :         if (m->poll_event != event) {
      33      266382 :                 m->poll_event = event;
      34      266382 :                 res |= EPOLLERR | EPOLLPRI;
      35             :         }
      36             : 
      37      528338 :         return res;
      38             : }
      39             : 
      40             : struct proc_fs_opts {
      41             :         int flag;
      42             :         const char *str;
      43             : };
      44             : 
      45   687028831 : static int show_sb_opts(struct seq_file *m, struct super_block *sb)
      46             : {
      47   687028831 :         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   687028831 :         const struct proc_fs_opts *fs_infop;
      55             : 
      56  3434425991 :         for (fs_infop = fs_opts; fs_infop->flag; fs_infop++) {
      57  2746556965 :                 if (sb->s_flags & fs_infop->flag)
      58        4037 :                         seq_puts(m, fs_infop->str);
      59             :         }
      60             : 
      61   687869026 :         return security_sb_show_options(m, sb);
      62             : }
      63             : 
      64   687727264 : static void show_mnt_opts(struct seq_file *m, struct vfsmount *mnt)
      65             : {
      66   687727264 :         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   687727264 :         const struct proc_fs_opts *fs_infop;
      77             : 
      78  5493403362 :         for (fs_infop = mnt_opts; fs_infop->flag; fs_infop++) {
      79  4805642790 :                 if (mnt->mnt_flags & fs_infop->flag)
      80  1088199642 :                         seq_puts(m, fs_infop->str);
      81             :         }
      82             : 
      83   687760572 :         if (is_idmapped_mnt(mnt))
      84        1230 :                 seq_puts(m, ",idmapped");
      85   687732090 : }
      86             : 
      87             : static inline void mangle(struct seq_file *m, const char *s)
      88             : {
      89   631500242 :         seq_escape(m, s, " \t\n\\#");
      90   631935010 : }
      91             : 
      92   687967104 : static void show_type(struct seq_file *m, struct super_block *sb)
      93             : {
      94   687967104 :         mangle(m, sb->s_type->name);
      95   687015004 :         if (sb->s_subtype) {
      96           0 :                 seq_putc(m, '.');
      97           0 :                 mangle(m, sb->s_subtype);
      98             :         }
      99   687015004 : }
     100             : 
     101   640935608 : static int show_vfsmnt(struct seq_file *m, struct vfsmount *mnt)
     102             : {
     103   640935608 :         struct proc_mounts *p = m->private;
     104   640935608 :         struct mount *r = real_mount(mnt);
     105   640935608 :         struct path mnt_path = { .dentry = mnt->mnt_root, .mnt = mnt };
     106   640935608 :         struct super_block *sb = mnt_path.dentry->d_sb;
     107   640935608 :         int err;
     108             : 
     109   640935608 :         if (sb->s_op->show_devname) {
     110    57524887 :                 err = sb->s_op->show_devname(m, mnt_path.dentry);
     111    57565054 :                 if (err)
     112           0 :                         goto out;
     113             :         } else {
     114   583410721 :                 mangle(m, r->mnt_devname ? r->mnt_devname : "none");
     115             :         }
     116   641369677 :         seq_putc(m, ' ');
     117             :         /* mountpoints outside of chroot jail will give SEQ_SKIP on this */
     118   641477255 :         err = seq_path_root(m, &mnt_path, &p->root, " \t\n\\");
     119   641915521 :         if (err)
     120     7034589 :                 goto out;
     121   634880932 :         seq_putc(m, ' ');
     122   634823330 :         show_type(m, sb);
     123   903746043 :         seq_puts(m, __mnt_is_readonly(mnt) ? " ro" : " rw");
     124   634190584 :         err = show_sb_opts(m, sb);
     125   634661501 :         if (err)
     126           0 :                 goto out;
     127   634661501 :         show_mnt_opts(m, mnt);
     128   634627572 :         if (sb->s_op->show_options)
     129   606474906 :                 err = sb->s_op->show_options(m, mnt_path.dentry);
     130   634421745 :         seq_puts(m, " 0 0\n");
     131   641344447 : out:
     132   641344447 :         return err;
     133             : }
     134             : 
     135    53776894 : static int show_mountinfo(struct seq_file *m, struct vfsmount *mnt)
     136             : {
     137    53776894 :         struct proc_mounts *p = m->private;
     138    53776894 :         struct mount *r = real_mount(mnt);
     139    53776894 :         struct super_block *sb = mnt->mnt_sb;
     140    53776894 :         struct path mnt_path = { .dentry = mnt->mnt_root, .mnt = mnt };
     141    53776894 :         int err;
     142             : 
     143    53776894 :         seq_printf(m, "%i %i %u:%u ", r->mnt_id, r->mnt_parent->mnt_id,
     144    53776894 :                    MAJOR(sb->s_dev), MINOR(sb->s_dev));
     145    53484554 :         if (sb->s_op->show_path) {
     146     5864578 :                 err = sb->s_op->show_path(m, mnt->mnt_root);
     147     5867445 :                 if (err)
     148           0 :                         goto out;
     149             :         } else {
     150    47619976 :                 seq_dentry(m, mnt->mnt_root, " \t\n\\");
     151             :         }
     152    53688202 :         seq_putc(m, ' ');
     153             : 
     154             :         /* mountpoints outside of chroot jail will give SEQ_SKIP on this */
     155    53671864 :         err = seq_path_root(m, &mnt_path, &p->root, " \t\n\\");
     156    53756862 :         if (err)
     157      579192 :                 goto out;
     158             : 
     159    75625612 :         seq_puts(m, mnt->mnt_flags & MNT_READONLY ? " ro" : " rw");
     160    53164502 :         show_mnt_opts(m, mnt);
     161             : 
     162             :         /* Tagged fields ("foo:X" or "bar") */
     163    53116718 :         if (IS_MNT_SHARED(r))
     164    53048003 :                 seq_printf(m, " shared:%i", r->mnt_group_id);
     165    53155463 :         if (IS_MNT_SLAVE(r)) {
     166       63928 :                 int master = r->mnt_master->mnt_group_id;
     167       63928 :                 int dom = get_dominating_id(r, &p->root);
     168       63902 :                 seq_printf(m, " master:%i", master);
     169       63900 :                 if (dom && dom != master)
     170           0 :                         seq_printf(m, " propagate_from:%i", dom);
     171             :         }
     172    53155435 :         if (IS_MNT_UNBINDABLE(r))
     173         432 :                 seq_puts(m, " unbindable");
     174             : 
     175             :         /* Filesystem specific data */
     176    53155435 :         seq_puts(m, " - ");
     177    53174946 :         show_type(m, sb);
     178    52792279 :         seq_putc(m, ' ');
     179    52808537 :         if (sb->s_op->show_devname) {
     180     4719016 :                 err = sb->s_op->show_devname(m, mnt->mnt_root);
     181     4738393 :                 if (err)
     182           0 :                         goto out;
     183             :         } else {
     184    48089521 :                 mangle(m, r->mnt_devname ? r->mnt_devname : "none");
     185             :         }
     186   105736999 :         seq_puts(m, sb_rdonly(sb) ? " ro" : " rw");
     187    52905569 :         err = show_sb_opts(m, sb);
     188    53160680 :         if (err)
     189           0 :                 goto out;
     190    53160680 :         if (sb->s_op->show_options)
     191    50798280 :                 err = sb->s_op->show_options(m, mnt->mnt_root);
     192    52873397 :         seq_putc(m, '\n');
     193    53377361 : out:
     194    53377361 :         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     7616735 : static int mounts_open_common(struct inode *inode, struct file *file,
     243             :                               int (*show)(struct seq_file *, struct vfsmount *))
     244             : {
     245     7616735 :         struct task_struct *task = get_proc_task(inode);
     246     7635391 :         struct nsproxy *nsp;
     247     7635391 :         struct mnt_namespace *ns = NULL;
     248     7635391 :         struct path root;
     249     7635391 :         struct proc_mounts *p;
     250     7635391 :         struct seq_file *m;
     251     7635391 :         int ret = -EINVAL;
     252             : 
     253     7635391 :         if (!task)
     254           0 :                 goto err;
     255             : 
     256     7635391 :         task_lock(task);
     257     7630240 :         nsp = task->nsproxy;
     258     7630240 :         if (!nsp || !nsp->mnt_ns) {
     259           0 :                 task_unlock(task);
     260           0 :                 put_task_struct(task);
     261           0 :                 goto err;
     262             :         }
     263     7630240 :         ns = nsp->mnt_ns;
     264     7630240 :         get_mnt_ns(ns);
     265     7608327 :         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     7608327 :         get_fs_root(task->fs, &root);
     272     7640740 :         task_unlock(task);
     273     7640864 :         put_task_struct(task);
     274             : 
     275     7632405 :         ret = seq_open_private(file, &mounts_op, sizeof(struct proc_mounts));
     276     7629788 :         if (ret)
     277           0 :                 goto err_put_path;
     278             : 
     279     7629788 :         m = file->private_data;
     280     7629788 :         m->poll_event = ns->event;
     281             : 
     282     7629788 :         p = m->private;
     283     7629788 :         p->ns = ns;
     284     7629788 :         p->root = root;
     285     7629788 :         p->show = show;
     286     7629788 :         INIT_LIST_HEAD(&p->cursor.mnt_list);
     287     7629788 :         p->cursor.mnt.mnt_flags = MNT_CURSOR;
     288             : 
     289     7629788 :         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     7621774 : static int mounts_release(struct inode *inode, struct file *file)
     300             : {
     301     7621774 :         struct seq_file *m = file->private_data;
     302     7621774 :         struct proc_mounts *p = m->private;
     303     7621774 :         path_put(&p->root);
     304     7636211 :         mnt_cursor_del(p->ns, &p->cursor);
     305     7640377 :         put_mnt_ns(p->ns);
     306     7622762 :         return seq_release_private(inode, file);
     307             : }
     308             : 
     309     7040271 : static int mounts_open(struct inode *inode, struct file *file)
     310             : {
     311     7040271 :         return mounts_open_common(inode, file, show_vfsmnt);
     312             : }
     313             : 
     314      584230 : static int mountinfo_open(struct inode *inode, struct file *file)
     315             : {
     316      584230 :         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