summaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorEric W. Biederman <ebiederm@xmission.com>2016-09-22 21:00:36 -0400
committerEric W. Biederman <ebiederm@xmission.com>2016-09-22 21:00:36 -0400
commit78725596644be0181c46f55c52aadfb8c70bcdb7 (patch)
treebaaea28de07a45f932f7674cfcd6c83522940770 /kernel
parent93f0a88bd4ad99a515f500a09f4a489ff03073eb (diff)
parent6ad92bf63e45f97e306da48cd1cbce6e4fef1e5d (diff)
Merge branch 'nsfs-ioctls' into HEAD
From: Andrey Vagin <avagin@openvz.org> Each namespace has an owning user namespace and now there is not way to discover these relationships. Pid and user namepaces are hierarchical. There is no way to discover parent-child relationships too. Why we may want to know relationships between namespaces? One use would be visualization, in order to understand the running system. Another would be to answer the question: what capability does process X have to perform operations on a resource governed by namespace Y? One more use-case (which usually called abnormal) is checkpoint/restart. In CRIU we are going to dump and restore nested namespaces. There [1] was a discussion about which interface to choose to determing relationships between namespaces. Eric suggested to add two ioctl-s [2]: > Grumble, Grumble. I think this may actually a case for creating ioctls > for these two cases. Now that random nsfs file descriptors are bind > mountable the original reason for using proc files is not as pressing. > > One ioctl for the user namespace that owns a file descriptor. > One ioctl for the parent namespace of a namespace file descriptor. Here is an implementaions of these ioctl-s. $ man man7/namespaces.7 ... Since Linux 4.X, the following ioctl(2) calls are supported for namespace file descriptors. The correct syntax is: fd = ioctl(ns_fd, ioctl_type); where ioctl_type is one of the following: NS_GET_USERNS Returns a file descriptor that refers to an owning user namesā€ pace. NS_GET_PARENT Returns a file descriptor that refers to a parent namespace. This ioctl(2) can be used for pid and user namespaces. For user namespaces, NS_GET_PARENT and NS_GET_USERNS have the same meaning. In addition to generic ioctl(2) errors, the following specific ones can occur: EINVAL NS_GET_PARENT was called for a nonhierarchical namespace. EPERM The requested namespace is outside of the current namespace scope. [1] https://lkml.org/lkml/2016/7/6/158 [2] https://lkml.org/lkml/2016/7/9/101 Changes for v2: * don't return ENOENT for init_user_ns and init_pid_ns. There is nothing outside of the init namespace, so we can return EPERM in this case too. > The fewer special cases the easier the code is to get > correct, and the easier it is to read. // Eric Changes for v3: * rename ns->get_owner() to ns->owner(). get_* usually means that it grabs a reference. Cc: "Eric W. Biederman" <ebiederm@xmission.com> Cc: James Bottomley <James.Bottomley@HansenPartnership.com> Cc: "Michael Kerrisk (man-pages)" <mtk.manpages@gmail.com> Cc: "W. Trevor King" <wking@tremily.us> Cc: Alexander Viro <viro@zeniv.linux.org.uk> Cc: Serge Hallyn <serge.hallyn@canonical.com>
Diffstat (limited to 'kernel')
-rw-r--r--kernel/cgroup.c6
-rw-r--r--kernel/pid_namespace.c25
-rw-r--r--kernel/user_namespace.c25
-rw-r--r--kernel/utsname.c6
4 files changed, 62 insertions, 0 deletions
diff --git a/kernel/cgroup.c b/kernel/cgroup.c
index f1dd4b076210..d6504338e284 100644
--- a/kernel/cgroup.c
+++ b/kernel/cgroup.c
@@ -6421,12 +6421,18 @@ static void cgroupns_put(struct ns_common *ns)
6421 put_cgroup_ns(to_cg_ns(ns)); 6421 put_cgroup_ns(to_cg_ns(ns));
6422} 6422}
6423 6423
6424static struct user_namespace *cgroupns_owner(struct ns_common *ns)
6425{
6426 return to_cg_ns(ns)->user_ns;
6427}
6428
6424const struct proc_ns_operations cgroupns_operations = { 6429const struct proc_ns_operations cgroupns_operations = {
6425 .name = "cgroup", 6430 .name = "cgroup",
6426 .type = CLONE_NEWCGROUP, 6431 .type = CLONE_NEWCGROUP,
6427 .get = cgroupns_get, 6432 .get = cgroupns_get,
6428 .put = cgroupns_put, 6433 .put = cgroupns_put,
6429 .install = cgroupns_install, 6434 .install = cgroupns_install,
6435 .owner = cgroupns_owner,
6430}; 6436};
6431 6437
6432static __init int cgroup_namespaces_init(void) 6438static __init int cgroup_namespaces_init(void)
diff --git a/kernel/pid_namespace.c b/kernel/pid_namespace.c
index 7542b28cc929..df9e8e9e0be7 100644
--- a/kernel/pid_namespace.c
+++ b/kernel/pid_namespace.c
@@ -405,12 +405,37 @@ static int pidns_install(struct nsproxy *nsproxy, struct ns_common *ns)
405 return 0; 405 return 0;
406} 406}
407 407
408static struct ns_common *pidns_get_parent(struct ns_common *ns)
409{
410 struct pid_namespace *active = task_active_pid_ns(current);
411 struct pid_namespace *pid_ns, *p;
412
413 /* See if the parent is in the current namespace */
414 pid_ns = p = to_pid_ns(ns)->parent;
415 for (;;) {
416 if (!p)
417 return ERR_PTR(-EPERM);
418 if (p == active)
419 break;
420 p = p->parent;
421 }
422
423 return &get_pid_ns(pid_ns)->ns;
424}
425
426static struct user_namespace *pidns_owner(struct ns_common *ns)
427{
428 return to_pid_ns(ns)->user_ns;
429}
430
408const struct proc_ns_operations pidns_operations = { 431const struct proc_ns_operations pidns_operations = {
409 .name = "pid", 432 .name = "pid",
410 .type = CLONE_NEWPID, 433 .type = CLONE_NEWPID,
411 .get = pidns_get, 434 .get = pidns_get,
412 .put = pidns_put, 435 .put = pidns_put,
413 .install = pidns_install, 436 .install = pidns_install,
437 .owner = pidns_owner,
438 .get_parent = pidns_get_parent,
414}; 439};
415 440
416static __init int pid_namespaces_init(void) 441static __init int pid_namespaces_init(void)
diff --git a/kernel/user_namespace.c b/kernel/user_namespace.c
index f2c5ba5505f1..86b7854fec8e 100644
--- a/kernel/user_namespace.c
+++ b/kernel/user_namespace.c
@@ -1050,12 +1050,37 @@ static int userns_install(struct nsproxy *nsproxy, struct ns_common *ns)
1050 return commit_creds(cred); 1050 return commit_creds(cred);
1051} 1051}
1052 1052
1053struct ns_common *ns_get_owner(struct ns_common *ns)
1054{
1055 struct user_namespace *my_user_ns = current_user_ns();
1056 struct user_namespace *owner, *p;
1057
1058 /* See if the owner is in the current user namespace */
1059 owner = p = ns->ops->owner(ns);
1060 for (;;) {
1061 if (!p)
1062 return ERR_PTR(-EPERM);
1063 if (p == my_user_ns)
1064 break;
1065 p = p->parent;
1066 }
1067
1068 return &get_user_ns(owner)->ns;
1069}
1070
1071static struct user_namespace *userns_owner(struct ns_common *ns)
1072{
1073 return to_user_ns(ns)->parent;
1074}
1075
1053const struct proc_ns_operations userns_operations = { 1076const struct proc_ns_operations userns_operations = {
1054 .name = "user", 1077 .name = "user",
1055 .type = CLONE_NEWUSER, 1078 .type = CLONE_NEWUSER,
1056 .get = userns_get, 1079 .get = userns_get,
1057 .put = userns_put, 1080 .put = userns_put,
1058 .install = userns_install, 1081 .install = userns_install,
1082 .owner = userns_owner,
1083 .get_parent = ns_get_owner,
1059}; 1084};
1060 1085
1061static __init int user_namespaces_init(void) 1086static __init int user_namespaces_init(void)
diff --git a/kernel/utsname.c b/kernel/utsname.c
index 35587b76faa3..6976cd47dcf6 100644
--- a/kernel/utsname.c
+++ b/kernel/utsname.c
@@ -154,10 +154,16 @@ static int utsns_install(struct nsproxy *nsproxy, struct ns_common *new)
154 return 0; 154 return 0;
155} 155}
156 156
157static struct user_namespace *utsns_owner(struct ns_common *ns)
158{
159 return to_uts_ns(ns)->user_ns;
160}
161
157const struct proc_ns_operations utsns_operations = { 162const struct proc_ns_operations utsns_operations = {
158 .name = "uts", 163 .name = "uts",
159 .type = CLONE_NEWUTS, 164 .type = CLONE_NEWUTS,
160 .get = utsns_get, 165 .get = utsns_get,
161 .put = utsns_put, 166 .put = utsns_put,
162 .install = utsns_install, 167 .install = utsns_install,
168 .owner = utsns_owner,
163}; 169};