linux/fs/nsfs.c
<<
>>
Prefs
   1#include <linux/mount.h>
   2#include <linux/file.h>
   3#include <linux/fs.h>
   4#include <linux/proc_ns.h>
   5#include <linux/magic.h>
   6#include <linux/ktime.h>
   7#include <linux/seq_file.h>
   8#include <linux/user_namespace.h>
   9#include <linux/nsfs.h>
  10
  11static struct vfsmount *nsfs_mnt;
  12
  13static long ns_ioctl(struct file *filp, unsigned int ioctl,
  14                        unsigned long arg);
  15static const struct file_operations ns_file_operations = {
  16        .llseek         = no_llseek,
  17        .unlocked_ioctl = ns_ioctl,
  18};
  19
  20static char *ns_dname(struct dentry *dentry, char *buffer, int buflen)
  21{
  22        struct inode *inode = d_inode(dentry);
  23        const struct proc_ns_operations *ns_ops = dentry->d_fsdata;
  24
  25        return dynamic_dname(dentry, buffer, buflen, "%s:[%lu]",
  26                ns_ops->name, inode->i_ino);
  27}
  28
  29static void ns_prune_dentry(struct dentry *dentry)
  30{
  31        struct inode *inode = d_inode(dentry);
  32        if (inode) {
  33                struct ns_common *ns = inode->i_private;
  34                atomic_long_set(&ns->stashed, 0);
  35        }
  36}
  37
  38const struct dentry_operations ns_dentry_operations =
  39{
  40        .d_prune        = ns_prune_dentry,
  41        .d_delete       = always_delete_dentry,
  42        .d_dname        = ns_dname,
  43};
  44
  45static void nsfs_evict(struct inode *inode)
  46{
  47        struct ns_common *ns = inode->i_private;
  48        clear_inode(inode);
  49        ns->ops->put(ns);
  50}
  51
  52static void *__ns_get_path(struct path *path, struct ns_common *ns)
  53{
  54        struct vfsmount *mnt = nsfs_mnt;
  55        struct qstr qname = { .name = "", };
  56        struct dentry *dentry;
  57        struct inode *inode;
  58        unsigned long d;
  59
  60        rcu_read_lock();
  61        d = atomic_long_read(&ns->stashed);
  62        if (!d)
  63                goto slow;
  64        dentry = (struct dentry *)d;
  65        if (!lockref_get_not_dead(&dentry->d_lockref))
  66                goto slow;
  67        rcu_read_unlock();
  68        ns->ops->put(ns);
  69got_it:
  70        path->mnt = mntget(mnt);
  71        path->dentry = dentry;
  72        return NULL;
  73slow:
  74        rcu_read_unlock();
  75        inode = new_inode_pseudo(mnt->mnt_sb);
  76        if (!inode) {
  77                ns->ops->put(ns);
  78                return ERR_PTR(-ENOMEM);
  79        }
  80        inode->i_ino = ns->inum;
  81        inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode);
  82        inode->i_flags |= S_IMMUTABLE;
  83        inode->i_mode = S_IFREG | S_IRUGO;
  84        inode->i_fop = &ns_file_operations;
  85        inode->i_private = ns;
  86
  87        dentry = d_alloc_pseudo(mnt->mnt_sb, &qname);
  88        if (!dentry) {
  89                iput(inode);
  90                return ERR_PTR(-ENOMEM);
  91        }
  92        d_instantiate(dentry, inode);
  93        dentry->d_fsdata = (void *)ns->ops;
  94        d = atomic_long_cmpxchg(&ns->stashed, 0, (unsigned long)dentry);
  95        if (d) {
  96                d_delete(dentry);       /* make sure ->d_prune() does nothing */
  97                dput(dentry);
  98                cpu_relax();
  99                return ERR_PTR(-EAGAIN);
 100        }
 101        goto got_it;
 102}
 103
 104void *ns_get_path(struct path *path, struct task_struct *task,
 105                        const struct proc_ns_operations *ns_ops)
 106{
 107        struct ns_common *ns;
 108        void *ret;
 109
 110again:
 111        ns = ns_ops->get(task);
 112        if (!ns)
 113                return ERR_PTR(-ENOENT);
 114
 115        ret = __ns_get_path(path, ns);
 116        if (IS_ERR(ret) && PTR_ERR(ret) == -EAGAIN)
 117                goto again;
 118        return ret;
 119}
 120
 121static int open_related_ns(struct ns_common *ns,
 122                   struct ns_common *(*get_ns)(struct ns_common *ns))
 123{
 124        struct path path = {};
 125        struct file *f;
 126        void *err;
 127        int fd;
 128
 129        fd = get_unused_fd_flags(O_CLOEXEC);
 130        if (fd < 0)
 131                return fd;
 132
 133        while (1) {
 134                struct ns_common *relative;
 135
 136                relative = get_ns(ns);
 137                if (IS_ERR(relative)) {
 138                        put_unused_fd(fd);
 139                        return PTR_ERR(relative);
 140                }
 141
 142                err = __ns_get_path(&path, relative);
 143                if (IS_ERR(err) && PTR_ERR(err) == -EAGAIN)
 144                        continue;
 145                break;
 146        }
 147        if (IS_ERR(err)) {
 148                put_unused_fd(fd);
 149                return PTR_ERR(err);
 150        }
 151
 152        f = dentry_open(&path, O_RDONLY, current_cred());
 153        path_put(&path);
 154        if (IS_ERR(f)) {
 155                put_unused_fd(fd);
 156                fd = PTR_ERR(f);
 157        } else
 158                fd_install(fd, f);
 159
 160        return fd;
 161}
 162
 163static long ns_ioctl(struct file *filp, unsigned int ioctl,
 164                        unsigned long arg)
 165{
 166        struct ns_common *ns = get_proc_ns(file_inode(filp));
 167
 168        switch (ioctl) {
 169        case NS_GET_USERNS:
 170                return open_related_ns(ns, ns_get_owner);
 171        case NS_GET_PARENT:
 172                if (!ns->ops->get_parent)
 173                        return -EINVAL;
 174                return open_related_ns(ns, ns->ops->get_parent);
 175        default:
 176                return -ENOTTY;
 177        }
 178}
 179
 180int ns_get_name(char *buf, size_t size, struct task_struct *task,
 181                        const struct proc_ns_operations *ns_ops)
 182{
 183        struct ns_common *ns;
 184        int res = -ENOENT;
 185        ns = ns_ops->get(task);
 186        if (ns) {
 187                res = snprintf(buf, size, "%s:[%u]", ns_ops->name, ns->inum);
 188                ns_ops->put(ns);
 189        }
 190        return res;
 191}
 192
 193struct file *proc_ns_fget(int fd)
 194{
 195        struct file *file;
 196
 197        file = fget(fd);
 198        if (!file)
 199                return ERR_PTR(-EBADF);
 200
 201        if (file->f_op != &ns_file_operations)
 202                goto out_invalid;
 203
 204        return file;
 205
 206out_invalid:
 207        fput(file);
 208        return ERR_PTR(-EINVAL);
 209}
 210
 211static int nsfs_show_path(struct seq_file *seq, struct dentry *dentry)
 212{
 213        struct inode *inode = d_inode(dentry);
 214        const struct proc_ns_operations *ns_ops = dentry->d_fsdata;
 215
 216        seq_printf(seq, "%s:[%lu]", ns_ops->name, inode->i_ino);
 217        return 0;
 218}
 219
 220static const struct super_operations nsfs_ops = {
 221        .statfs = simple_statfs,
 222        .evict_inode = nsfs_evict,
 223        .show_path = nsfs_show_path,
 224};
 225static struct dentry *nsfs_mount(struct file_system_type *fs_type,
 226                        int flags, const char *dev_name, void *data)
 227{
 228        return mount_pseudo(fs_type, "nsfs:", &nsfs_ops,
 229                        &ns_dentry_operations, NSFS_MAGIC);
 230}
 231static struct file_system_type nsfs = {
 232        .name = "nsfs",
 233        .mount = nsfs_mount,
 234        .kill_sb = kill_anon_super,
 235};
 236
 237void __init nsfs_init(void)
 238{
 239        nsfs_mnt = kern_mount(&nsfs);
 240        if (IS_ERR(nsfs_mnt))
 241                panic("can't set nsfs up\n");
 242        nsfs_mnt->mnt_sb->s_flags &= ~MS_NOUSER;
 243}
 244