LCOV - code coverage report
Current view: top level - fs - nsfs.c (source / functions) Hit Total Coverage
Test: landlock.info Lines: 65 155 41.9 %
Date: 2021-04-22 12:43:58 Functions: 8 16 50.0 %

          Line data    Source code
       1             : // SPDX-License-Identifier: GPL-2.0
       2             : #include <linux/mount.h>
       3             : #include <linux/pseudo_fs.h>
       4             : #include <linux/file.h>
       5             : #include <linux/fs.h>
       6             : #include <linux/proc_fs.h>
       7             : #include <linux/proc_ns.h>
       8             : #include <linux/magic.h>
       9             : #include <linux/ktime.h>
      10             : #include <linux/seq_file.h>
      11             : #include <linux/user_namespace.h>
      12             : #include <linux/nsfs.h>
      13             : #include <linux/uaccess.h>
      14             : 
      15             : #include "internal.h"
      16             : 
      17             : static struct vfsmount *nsfs_mnt;
      18             : 
      19             : static long ns_ioctl(struct file *filp, unsigned int ioctl,
      20             :                         unsigned long arg);
      21             : static const struct file_operations ns_file_operations = {
      22             :         .llseek         = no_llseek,
      23             :         .unlocked_ioctl = ns_ioctl,
      24             : };
      25             : 
      26           0 : static char *ns_dname(struct dentry *dentry, char *buffer, int buflen)
      27             : {
      28           0 :         struct inode *inode = d_inode(dentry);
      29           0 :         const struct proc_ns_operations *ns_ops = dentry->d_fsdata;
      30             : 
      31           0 :         return dynamic_dname(dentry, buffer, buflen, "%s:[%lu]",
      32             :                 ns_ops->name, inode->i_ino);
      33             : }
      34             : 
      35           3 : static void ns_prune_dentry(struct dentry *dentry)
      36             : {
      37           3 :         struct inode *inode = d_inode(dentry);
      38           3 :         if (inode) {
      39           3 :                 struct ns_common *ns = inode->i_private;
      40           3 :                 atomic_long_set(&ns->stashed, 0);
      41             :         }
      42           3 : }
      43             : 
      44             : const struct dentry_operations ns_dentry_operations =
      45             : {
      46             :         .d_prune        = ns_prune_dentry,
      47             :         .d_delete       = always_delete_dentry,
      48             :         .d_dname        = ns_dname,
      49             : };
      50             : 
      51           3 : static void nsfs_evict(struct inode *inode)
      52             : {
      53           3 :         struct ns_common *ns = inode->i_private;
      54           3 :         clear_inode(inode);
      55           3 :         ns->ops->put(ns);
      56           3 : }
      57             : 
      58           3 : static int __ns_get_path(struct path *path, struct ns_common *ns)
      59             : {
      60           3 :         struct vfsmount *mnt = nsfs_mnt;
      61           3 :         struct dentry *dentry;
      62           3 :         struct inode *inode;
      63           3 :         unsigned long d;
      64             : 
      65           3 :         rcu_read_lock();
      66           3 :         d = atomic_long_read(&ns->stashed);
      67           3 :         if (!d)
      68           3 :                 goto slow;
      69           0 :         dentry = (struct dentry *)d;
      70           0 :         if (!lockref_get_not_dead(&dentry->d_lockref))
      71           0 :                 goto slow;
      72           0 :         rcu_read_unlock();
      73           0 :         ns->ops->put(ns);
      74           3 : got_it:
      75           3 :         path->mnt = mntget(mnt);
      76           3 :         path->dentry = dentry;
      77           3 :         return 0;
      78           3 : slow:
      79           3 :         rcu_read_unlock();
      80           3 :         inode = new_inode_pseudo(mnt->mnt_sb);
      81           3 :         if (!inode) {
      82           0 :                 ns->ops->put(ns);
      83           0 :                 return -ENOMEM;
      84             :         }
      85           3 :         inode->i_ino = ns->inum;
      86           3 :         inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode);
      87           3 :         inode->i_flags |= S_IMMUTABLE;
      88           3 :         inode->i_mode = S_IFREG | S_IRUGO;
      89           3 :         inode->i_fop = &ns_file_operations;
      90           3 :         inode->i_private = ns;
      91             : 
      92           3 :         dentry = d_alloc_anon(mnt->mnt_sb);
      93           3 :         if (!dentry) {
      94           0 :                 iput(inode);
      95           0 :                 return -ENOMEM;
      96             :         }
      97           3 :         d_instantiate(dentry, inode);
      98           3 :         dentry->d_fsdata = (void *)ns->ops;
      99           3 :         d = atomic_long_cmpxchg(&ns->stashed, 0, (unsigned long)dentry);
     100           3 :         if (d) {
     101           0 :                 d_delete(dentry);       /* make sure ->d_prune() does nothing */
     102           0 :                 dput(dentry);
     103           0 :                 cpu_relax();
     104           0 :                 return -EAGAIN;
     105             :         }
     106           3 :         goto got_it;
     107             : }
     108             : 
     109           3 : int ns_get_path_cb(struct path *path, ns_get_path_helper_t *ns_get_cb,
     110             :                      void *private_data)
     111             : {
     112           3 :         int ret;
     113             : 
     114           3 :         do {
     115           3 :                 struct ns_common *ns = ns_get_cb(private_data);
     116           3 :                 if (!ns)
     117             :                         return -ENOENT;
     118           3 :                 ret = __ns_get_path(path, ns);
     119           3 :         } while (ret == -EAGAIN);
     120             : 
     121             :         return ret;
     122             : }
     123             : 
     124             : struct ns_get_path_task_args {
     125             :         const struct proc_ns_operations *ns_ops;
     126             :         struct task_struct *task;
     127             : };
     128             : 
     129           3 : static struct ns_common *ns_get_path_task(void *private_data)
     130             : {
     131           3 :         struct ns_get_path_task_args *args = private_data;
     132             : 
     133           3 :         return args->ns_ops->get(args->task);
     134             : }
     135             : 
     136           3 : int ns_get_path(struct path *path, struct task_struct *task,
     137             :                   const struct proc_ns_operations *ns_ops)
     138             : {
     139           3 :         struct ns_get_path_task_args args = {
     140             :                 .ns_ops = ns_ops,
     141             :                 .task   = task,
     142             :         };
     143             : 
     144           3 :         return ns_get_path_cb(path, ns_get_path_task, &args);
     145             : }
     146             : 
     147           0 : int open_related_ns(struct ns_common *ns,
     148             :                    struct ns_common *(*get_ns)(struct ns_common *ns))
     149             : {
     150           0 :         struct path path = {};
     151           0 :         struct file *f;
     152           0 :         int err;
     153           0 :         int fd;
     154             : 
     155           0 :         fd = get_unused_fd_flags(O_CLOEXEC);
     156           0 :         if (fd < 0)
     157             :                 return fd;
     158             : 
     159           0 :         do {
     160           0 :                 struct ns_common *relative;
     161             : 
     162           0 :                 relative = get_ns(ns);
     163           0 :                 if (IS_ERR(relative)) {
     164           0 :                         put_unused_fd(fd);
     165           0 :                         return PTR_ERR(relative);
     166             :                 }
     167             : 
     168           0 :                 err = __ns_get_path(&path, relative);
     169           0 :         } while (err == -EAGAIN);
     170             : 
     171           0 :         if (err) {
     172           0 :                 put_unused_fd(fd);
     173           0 :                 return err;
     174             :         }
     175             : 
     176           0 :         f = dentry_open(&path, O_RDONLY, current_cred());
     177           0 :         path_put(&path);
     178           0 :         if (IS_ERR(f)) {
     179           0 :                 put_unused_fd(fd);
     180           0 :                 fd = PTR_ERR(f);
     181             :         } else
     182           0 :                 fd_install(fd, f);
     183             : 
     184             :         return fd;
     185             : }
     186             : EXPORT_SYMBOL_GPL(open_related_ns);
     187             : 
     188           0 : static long ns_ioctl(struct file *filp, unsigned int ioctl,
     189             :                         unsigned long arg)
     190             : {
     191           0 :         struct user_namespace *user_ns;
     192           0 :         struct ns_common *ns = get_proc_ns(file_inode(filp));
     193           0 :         uid_t __user *argp;
     194           0 :         uid_t uid;
     195             : 
     196           0 :         switch (ioctl) {
     197           0 :         case NS_GET_USERNS:
     198           0 :                 return open_related_ns(ns, ns_get_owner);
     199           0 :         case NS_GET_PARENT:
     200           0 :                 if (!ns->ops->get_parent)
     201             :                         return -EINVAL;
     202           0 :                 return open_related_ns(ns, ns->ops->get_parent);
     203           0 :         case NS_GET_NSTYPE:
     204           0 :                 return ns->ops->type;
     205           0 :         case NS_GET_OWNER_UID:
     206           0 :                 if (ns->ops->type != CLONE_NEWUSER)
     207             :                         return -EINVAL;
     208           0 :                 user_ns = container_of(ns, struct user_namespace, ns);
     209           0 :                 argp = (uid_t __user *) arg;
     210           0 :                 uid = from_kuid_munged(current_user_ns(), user_ns->owner);
     211           0 :                 return put_user(uid, argp);
     212             :         default:
     213             :                 return -ENOTTY;
     214             :         }
     215             : }
     216             : 
     217           0 : int ns_get_name(char *buf, size_t size, struct task_struct *task,
     218             :                         const struct proc_ns_operations *ns_ops)
     219             : {
     220           0 :         struct ns_common *ns;
     221           0 :         int res = -ENOENT;
     222           0 :         const char *name;
     223           0 :         ns = ns_ops->get(task);
     224           0 :         if (ns) {
     225           0 :                 name = ns_ops->real_ns_name ? : ns_ops->name;
     226           0 :                 res = snprintf(buf, size, "%s:[%u]", name, ns->inum);
     227           0 :                 ns_ops->put(ns);
     228             :         }
     229           0 :         return res;
     230             : }
     231             : 
     232           0 : bool proc_ns_file(const struct file *file)
     233             : {
     234           0 :         return file->f_op == &ns_file_operations;
     235             : }
     236             : 
     237           0 : struct file *proc_ns_fget(int fd)
     238             : {
     239           0 :         struct file *file;
     240             : 
     241           0 :         file = fget(fd);
     242           0 :         if (!file)
     243           0 :                 return ERR_PTR(-EBADF);
     244             : 
     245           0 :         if (file->f_op != &ns_file_operations)
     246           0 :                 goto out_invalid;
     247             : 
     248             :         return file;
     249             : 
     250           0 : out_invalid:
     251           0 :         fput(file);
     252           0 :         return ERR_PTR(-EINVAL);
     253             : }
     254             : 
     255             : /**
     256             :  * ns_match() - Returns true if current namespace matches dev/ino provided.
     257             :  * @ns_common: current ns
     258             :  * @dev: dev_t from nsfs that will be matched against current nsfs
     259             :  * @ino: ino_t from nsfs that will be matched against current nsfs
     260             :  *
     261             :  * Return: true if dev and ino matches the current nsfs.
     262             :  */
     263           0 : bool ns_match(const struct ns_common *ns, dev_t dev, ino_t ino)
     264             : {
     265           0 :         return (ns->inum == ino) && (nsfs_mnt->mnt_sb->s_dev == dev);
     266             : }
     267             : 
     268             : 
     269           0 : static int nsfs_show_path(struct seq_file *seq, struct dentry *dentry)
     270             : {
     271           0 :         struct inode *inode = d_inode(dentry);
     272           0 :         const struct proc_ns_operations *ns_ops = dentry->d_fsdata;
     273             : 
     274           0 :         seq_printf(seq, "%s:[%lu]", ns_ops->name, inode->i_ino);
     275           0 :         return 0;
     276             : }
     277             : 
     278             : static const struct super_operations nsfs_ops = {
     279             :         .statfs = simple_statfs,
     280             :         .evict_inode = nsfs_evict,
     281             :         .show_path = nsfs_show_path,
     282             : };
     283             : 
     284           1 : static int nsfs_init_fs_context(struct fs_context *fc)
     285             : {
     286           1 :         struct pseudo_fs_context *ctx = init_pseudo(fc, NSFS_MAGIC);
     287           1 :         if (!ctx)
     288             :                 return -ENOMEM;
     289           1 :         ctx->ops = &nsfs_ops;
     290           1 :         ctx->dops = &ns_dentry_operations;
     291           1 :         return 0;
     292             : }
     293             : 
     294             : static struct file_system_type nsfs = {
     295             :         .name = "nsfs",
     296             :         .init_fs_context = nsfs_init_fs_context,
     297             :         .kill_sb = kill_anon_super,
     298             : };
     299             : 
     300           1 : void __init nsfs_init(void)
     301             : {
     302           1 :         nsfs_mnt = kern_mount(&nsfs);
     303           1 :         if (IS_ERR(nsfs_mnt))
     304           0 :                 panic("can't set nsfs up\n");
     305           1 :         nsfs_mnt->mnt_sb->s_flags &= ~SB_NOUSER;
     306           1 : }

Generated by: LCOV version 1.14