From 6786741dbf99e44fb0c0ed85a37582b8a26f1c3b Mon Sep 17 00:00:00 2001 From: Andrey Vagin Date: Tue, 6 Sep 2016 00:47:14 -0700 Subject: 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 Link: https://lkml.org/lkml/2016/7/6/158 Signed-off-by: Andrei Vagin Signed-off-by: Eric W. Biederman --- include/uapi/linux/nsfs.h | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 include/uapi/linux/nsfs.h (limited to 'include/uapi') diff --git a/include/uapi/linux/nsfs.h b/include/uapi/linux/nsfs.h new file mode 100644 index 000000000000..5cacd5c1b5d7 --- /dev/null +++ b/include/uapi/linux/nsfs.h @@ -0,0 +1,11 @@ +#ifndef __LINUX_NSFS_H +#define __LINUX_NSFS_H + +#include + +#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 */ -- cgit v1.2.3 From a7306ed8d94af729ecef8b6e37506a1c6fc14788 Mon Sep 17 00:00:00 2001 From: Andrey Vagin Date: Tue, 6 Sep 2016 00:47:15 -0700 Subject: nsfs: add ioctl to get a parent namespace Pid and user namepaces are hierarchical. There is no way to discover parent-child relationships. In a future we will use this interface to dump and restore nested namespaces. Acked-by: Serge Hallyn Signed-off-by: Andrei Vagin Signed-off-by: Eric W. Biederman --- fs/nsfs.c | 4 ++++ include/linux/proc_ns.h | 1 + include/uapi/linux/nsfs.h | 2 ++ kernel/pid_namespace.c | 19 +++++++++++++++++++ kernel/user_namespace.c | 1 + 5 files changed, 27 insertions(+) (limited to 'include/uapi') diff --git a/fs/nsfs.c b/fs/nsfs.c index 3887da470f7e..fb7b397a1297 100644 --- a/fs/nsfs.c +++ b/fs/nsfs.c @@ -171,6 +171,10 @@ static long ns_ioctl(struct file *filp, unsigned int ioctl, switch (ioctl) { case NS_GET_USERNS: return open_related_ns(ns, ns_get_owner); + case NS_GET_PARENT: + if (!ns->ops->get_parent) + return -EINVAL; + return open_related_ns(ns, ns->ops->get_parent); default: return -ENOTTY; } diff --git a/include/linux/proc_ns.h b/include/linux/proc_ns.h index ca85a4348ffc..12cb8bd81d2d 100644 --- a/include/linux/proc_ns.h +++ b/include/linux/proc_ns.h @@ -19,6 +19,7 @@ struct proc_ns_operations { void (*put)(struct ns_common *ns); int (*install)(struct nsproxy *nsproxy, struct ns_common *ns); struct user_namespace *(*owner)(struct ns_common *ns); + struct ns_common *(*get_parent)(struct ns_common *ns); }; extern const struct proc_ns_operations netns_operations; diff --git a/include/uapi/linux/nsfs.h b/include/uapi/linux/nsfs.h index 5cacd5c1b5d7..3af617230d1b 100644 --- a/include/uapi/linux/nsfs.h +++ b/include/uapi/linux/nsfs.h @@ -7,5 +7,7 @@ /* Returns a file descriptor that refers to an owning user namespace */ #define NS_GET_USERNS _IO(NSIO, 0x1) +/* Returns a file descriptor that refers to a parent namespace */ +#define NS_GET_PARENT _IO(NSIO, 0x2) #endif /* __LINUX_NSFS_H */ diff --git a/kernel/pid_namespace.c b/kernel/pid_namespace.c index c02d744225e1..4fa2d56a936c 100644 --- a/kernel/pid_namespace.c +++ b/kernel/pid_namespace.c @@ -388,6 +388,24 @@ static int pidns_install(struct nsproxy *nsproxy, struct ns_common *ns) return 0; } +static struct ns_common *pidns_get_parent(struct ns_common *ns) +{ + struct pid_namespace *active = task_active_pid_ns(current); + struct pid_namespace *pid_ns, *p; + + /* See if the parent is in the current namespace */ + pid_ns = p = to_pid_ns(ns)->parent; + for (;;) { + if (!p) + return ERR_PTR(-EPERM); + if (p == active) + break; + p = p->parent; + } + + return &get_pid_ns(pid_ns)->ns; +} + static struct user_namespace *pidns_owner(struct ns_common *ns) { return to_pid_ns(ns)->user_ns; @@ -400,6 +418,7 @@ const struct proc_ns_operations pidns_operations = { .put = pidns_put, .install = pidns_install, .owner = pidns_owner, + .get_parent = pidns_get_parent, }; static __init int pid_namespaces_init(void) diff --git a/kernel/user_namespace.c b/kernel/user_namespace.c index 0ef683a03c20..a58a219b99c6 100644 --- a/kernel/user_namespace.c +++ b/kernel/user_namespace.c @@ -1034,6 +1034,7 @@ const struct proc_ns_operations userns_operations = { .put = userns_put, .install = userns_install, .owner = userns_owner, + .get_parent = ns_get_owner, }; static __init int user_namespaces_init(void) -- cgit v1.2.3