Quoting Andrei Vagin (ava...@openvz.org):
> From: Andrey Vagin <ava...@openvz.org>
> 
> Each namespace has an owning user namespace and now there is not way
> to discover these relationships.
> 
> Understending namespaces relationships allows to answer the question:
> what capability does process X have to perform operations on a resource
> governed by namespace Y?
> 
> After a long discussion, Eric W. Biederman proposed to use ioctl-s for
> this purpose.
> 
> The NS_GET_USERNS ioctl returns a file descriptor to an owning user
> namespace.
> It returns EPERM if a target namespace is outside of a current user
> namespace.
> 
> v2: rename parent to relative
> 
> Link: https://lkml.org/lkml/2016/7/6/158
> Signed-off-by: Andrei Vagin <ava...@openvz.org>

Acked-by: Serge Hallyn <se...@hallyn.com>

> ---
>  fs/nsfs.c                 | 95 
> ++++++++++++++++++++++++++++++++++++++++-------
>  include/uapi/linux/nsfs.h | 11 ++++++
>  2 files changed, 93 insertions(+), 13 deletions(-)
>  create mode 100644 include/uapi/linux/nsfs.h
> 
> diff --git a/fs/nsfs.c b/fs/nsfs.c
> index 8f20d60..be7d193 100644
> --- a/fs/nsfs.c
> +++ b/fs/nsfs.c
> @@ -5,11 +5,16 @@
>  #include <linux/magic.h>
>  #include <linux/ktime.h>
>  #include <linux/seq_file.h>
> +#include <linux/user_namespace.h>
> +#include <linux/nsfs.h>
>  
>  static struct vfsmount *nsfs_mnt;
>  
> +static long ns_ioctl(struct file *filp, unsigned int ioctl,
> +                     unsigned long arg);
>  static const struct file_operations ns_file_operations = {
>       .llseek         = no_llseek,
> +     .unlocked_ioctl = ns_ioctl,
>  };
>  
>  static char *ns_dname(struct dentry *dentry, char *buffer, int buflen)
> @@ -44,22 +49,14 @@ static void nsfs_evict(struct inode *inode)
>       ns->ops->put(ns);
>  }
>  
> -void *ns_get_path(struct path *path, struct task_struct *task,
> -                     const struct proc_ns_operations *ns_ops)
> +static void *__ns_get_path(struct path *path, struct ns_common *ns)
>  {
>       struct vfsmount *mnt = mntget(nsfs_mnt);
>       struct qstr qname = { .name = "", };
>       struct dentry *dentry;
>       struct inode *inode;
> -     struct ns_common *ns;
>       unsigned long d;
>  
> -again:
> -     ns = ns_ops->get(task);
> -     if (!ns) {
> -             mntput(mnt);
> -             return ERR_PTR(-ENOENT);
> -     }
>       rcu_read_lock();
>       d = atomic_long_read(&ns->stashed);
>       if (!d)
> @@ -68,7 +65,7 @@ again:
>       if (!lockref_get_not_dead(&dentry->d_lockref))
>               goto slow;
>       rcu_read_unlock();
> -     ns_ops->put(ns);
> +     ns->ops->put(ns);
>  got_it:
>       path->mnt = mnt;
>       path->dentry = dentry;
> @@ -77,7 +74,7 @@ slow:
>       rcu_read_unlock();
>       inode = new_inode_pseudo(mnt->mnt_sb);
>       if (!inode) {
> -             ns_ops->put(ns);
> +             ns->ops->put(ns);
>               mntput(mnt);
>               return ERR_PTR(-ENOMEM);
>       }
> @@ -95,17 +92,89 @@ slow:
>               return ERR_PTR(-ENOMEM);
>       }
>       d_instantiate(dentry, inode);
> -     dentry->d_fsdata = (void *)ns_ops;
> +     dentry->d_fsdata = (void *)ns->ops;
>       d = atomic_long_cmpxchg(&ns->stashed, 0, (unsigned long)dentry);
>       if (d) {
>               d_delete(dentry);       /* make sure ->d_prune() does nothing */
>               dput(dentry);
>               cpu_relax();
> -             goto again;
> +             return ERR_PTR(-EAGAIN);
>       }
>       goto got_it;
>  }
>  
> +void *ns_get_path(struct path *path, struct task_struct *task,
> +                     const struct proc_ns_operations *ns_ops)
> +{
> +     struct ns_common *ns;
> +     void *ret;
> +
> +again:
> +     ns = ns_ops->get(task);
> +     if (!ns)
> +             return ERR_PTR(-ENOENT);
> +
> +     ret = __ns_get_path(path, ns);
> +     if (IS_ERR(ret) && PTR_ERR(ret) == -EAGAIN)
> +             goto again;
> +     return ret;
> +}
> +
> +static int open_related_ns(struct ns_common *ns,
> +                struct ns_common *(*get_ns)(struct ns_common *ns))
> +{
> +     struct path path = {};
> +     struct file *f;
> +     void *err;
> +     int fd;
> +
> +     fd = get_unused_fd_flags(O_CLOEXEC);
> +     if (fd < 0)
> +             return fd;
> +
> +     while (1) {
> +             struct ns_common *relative;
> +
> +             relative = get_ns(ns);
> +             if (IS_ERR(relative)) {
> +                     put_unused_fd(fd);
> +                     return PTR_ERR(relative);
> +             }
> +
> +             err = __ns_get_path(&path, relative);
> +             if (IS_ERR(err) && PTR_ERR(err) == -EAGAIN)
> +                     continue;
> +             break;
> +     }
> +     if (IS_ERR(err)) {
> +             put_unused_fd(fd);
> +             return PTR_ERR(err);
> +     }
> +
> +     f = dentry_open(&path, O_RDONLY, current_cred());
> +     path_put(&path);
> +     if (IS_ERR(f)) {
> +             put_unused_fd(fd);
> +             fd = PTR_ERR(f);
> +     } else
> +             fd_install(fd, f);
> +
> +     return fd;
> +}
> +
> +static long ns_ioctl(struct file *filp, unsigned int ioctl,
> +                     unsigned long arg)
> +{
> +     struct ns_common *ns = get_proc_ns(file_inode(filp));
> +
> +     switch (ioctl) {
> +     case NS_GET_USERNS:
> +             return open_related_ns(ns, ns_get_owner);
> +     default:
> +             return -ENOTTY;
> +     }
> +}
> +
>  int ns_get_name(char *buf, size_t size, struct task_struct *task,
>                       const struct proc_ns_operations *ns_ops)
>  {
> diff --git a/include/uapi/linux/nsfs.h b/include/uapi/linux/nsfs.h
> new file mode 100644
> index 0000000..5cacd5c
> --- /dev/null
> +++ b/include/uapi/linux/nsfs.h
> @@ -0,0 +1,11 @@
> +#ifndef __LINUX_NSFS_H
> +#define __LINUX_NSFS_H
> +
> +#include <linux/ioctl.h>
> +
> +#define NSIO 0xb7
> +
> +/* Returns a file descriptor that refers to an owning user namespace */
> +#define NS_GET_USERNS        _IO(NSIO, 0x1)
> +
> +#endif /* __LINUX_NSFS_H */
> -- 
> 2.5.5
> 
> _______________________________________________
> Containers mailing list
> contain...@lists.linux-foundation.org
> https://lists.linuxfoundation.org/mailman/listinfo/containers

Reply via email to