Changes: We have no nsfs.c, so move the code to fs/proc/namespaces.c. Func __ns_get_path's replaced with analog __proc_ns_get_dentry, so pass additional arguments everywhere, skip EAGAIN part as we don't have it in proc_ns_get_dentry. I add expected resulting ns's proc_ns_operations to open_related_ns as get_ns gives us blind void* and we don't know if it is pid_namespace or user_namespace, and __proc_ns_get_dentry requires to know which.
https://jira.sw.ru/browse/PSBM-57362 ms commit 6786741dbf99 ("nsfs: add ioctl to get an owning user namespace for ns file descriptor") 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 v3: Add a missing mntput when returning -EAGAIN --EWB Acked-by: Serge Hallyn <se...@hallyn.com> Link: https://lkml.org/lkml/2016/7/6/158 Signed-off-by: Andrei Vagin <ava...@openvz.org> Signed-off-by: Eric W. Biederman <ebied...@xmission.com> Signed-off-by: Pavel Tikhomirov <ptikhomi...@virtuozzo.com> --- fs/proc/namespaces.c | 81 +++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 74 insertions(+), 7 deletions(-) diff --git a/fs/proc/namespaces.c b/fs/proc/namespaces.c index b0c6d0417433..121b76d3fcd0 100644 --- a/fs/proc/namespaces.c +++ b/fs/proc/namespaces.c @@ -13,7 +13,12 @@ #include <linux/pid_namespace.h> #include <linux/user_namespace.h> #include "internal.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) static const struct proc_ns_operations *ns_entries[] = { #ifdef CONFIG_NET_NS @@ -35,8 +40,11 @@ static const struct proc_ns_operations *ns_entries[] = { &mntns_operations, }; +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 const struct inode_operations ns_inode_operations = { @@ -64,18 +72,13 @@ const struct dentry_operations ns_dentry_operations = .d_dname = ns_dname, }; -static struct dentry *proc_ns_get_dentry(struct super_block *sb, - struct task_struct *task, const struct proc_ns_operations *ns_ops) +static struct dentry *__proc_ns_get_dentry(struct super_block *sb, + void *ns, const struct proc_ns_operations *ns_ops) { struct dentry *dentry, *result; struct inode *inode; struct proc_inode *ei; struct qstr qname = { .name = "", }; - void *ns; - - ns = ns_ops->get(task); - if (!ns) - return ERR_PTR(-ENOENT); dentry = d_alloc_pseudo(sb, &qname); if (!dentry) { @@ -113,6 +116,70 @@ static struct dentry *proc_ns_get_dentry(struct super_block *sb, return dentry; } +static struct dentry *proc_ns_get_dentry(struct super_block *sb, + struct task_struct *task, const struct proc_ns_operations *ns_ops) +{ + void *ns; + + ns = ns_ops->get(task); + if (!ns) + return ERR_PTR(-ENOENT); + + return __proc_ns_get_dentry(sb, ns, ns_ops); +} + +static int open_related_ns(struct vfsmount *mnt, struct proc_ns *ns, + const struct proc_ns_operations *relative_ns_ops, + void *(*get_ns)(void *ns, + const struct proc_ns_operations *ns_ops)) { + struct path path = {}; + struct file *f; + int fd; + void *relative; + + fd = get_unused_fd_flags(O_CLOEXEC); + if (fd < 0) + return fd; + + relative = get_ns(ns->ns, ns->ns_ops); + if (IS_ERR(relative)) { + put_unused_fd(fd); + return PTR_ERR(relative); + } + + path.mnt = mntget(mnt); + path.dentry = __proc_ns_get_dentry(mnt->mnt_sb, relative, relative_ns_ops); + if (IS_ERR(path.dentry)) { + mntput(mnt); + put_unused_fd(fd); + return PTR_ERR(path.dentry); + } + + 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 vfsmount *mnt = filp->f_path.mnt; + struct proc_ns *ns = get_proc_ns(file_inode(filp)); + + switch (ioctl) { + case NS_GET_USERNS: + return open_related_ns(mnt, ns, &userns_operations, ns_get_owner); + default: + return -ENOTTY; + } +} + static void *proc_ns_follow_link(struct dentry *dentry, struct nameidata *nd) { struct inode *inode = dentry->d_inode; -- 2.13.6 _______________________________________________ Devel mailing list Devel@openvz.org https://lists.openvz.org/mailman/listinfo/devel