aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndrey Vagin <avagin@openvz.org>2016-09-06 03:47:13 -0400
committerEric W. Biederman <ebiederm@xmission.com>2016-09-22 20:59:39 -0400
commitbcac25a58bfc6bd79191ac5d7afb49bea96da8c9 (patch)
tree28a8ae71b2939267deba0807bcbbed28e77470c0
parent29b4817d4018df78086157ea3a55c1d9424a7cfc (diff)
kernel: add a helper to get an owning user namespace for a namespace
Return -EPERM if an owning user namespace is outside of a process current user namespace. v2: In a first version ns_get_owner returned ENOENT for init_user_ns. This special cases was removed from this version. There is nothing outside of init_user_ns, so we can return EPERM. v3: rename ns->get_owner() to ns->owner(). get_* usually means that it grabs a reference. Acked-by: Serge Hallyn <serge@hallyn.com> Signed-off-by: Andrei Vagin <avagin@openvz.org> Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>
-rw-r--r--fs/namespace.c6
-rw-r--r--include/linux/proc_ns.h1
-rw-r--r--include/linux/user_namespace.h7
-rw-r--r--ipc/namespace.c6
-rw-r--r--kernel/cgroup.c6
-rw-r--r--kernel/pid_namespace.c6
-rw-r--r--kernel/user_namespace.c24
-rw-r--r--kernel/utsname.c6
-rw-r--r--net/core/net_namespace.c6
9 files changed, 68 insertions, 0 deletions
diff --git a/fs/namespace.c b/fs/namespace.c
index 7bb2cda3bfef..fea56f310547 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -3348,10 +3348,16 @@ static int mntns_install(struct nsproxy *nsproxy, struct ns_common *ns)
3348 return 0; 3348 return 0;
3349} 3349}
3350 3350
3351static struct user_namespace *mntns_owner(struct ns_common *ns)
3352{
3353 return to_mnt_ns(ns)->user_ns;
3354}
3355
3351const struct proc_ns_operations mntns_operations = { 3356const struct proc_ns_operations mntns_operations = {
3352 .name = "mnt", 3357 .name = "mnt",
3353 .type = CLONE_NEWNS, 3358 .type = CLONE_NEWNS,
3354 .get = mntns_get, 3359 .get = mntns_get,
3355 .put = mntns_put, 3360 .put = mntns_put,
3356 .install = mntns_install, 3361 .install = mntns_install,
3362 .owner = mntns_owner,
3357}; 3363};
diff --git a/include/linux/proc_ns.h b/include/linux/proc_ns.h
index de0e7719d4c5..ca85a4348ffc 100644
--- a/include/linux/proc_ns.h
+++ b/include/linux/proc_ns.h
@@ -18,6 +18,7 @@ struct proc_ns_operations {
18 struct ns_common *(*get)(struct task_struct *task); 18 struct ns_common *(*get)(struct task_struct *task);
19 void (*put)(struct ns_common *ns); 19 void (*put)(struct ns_common *ns);
20 int (*install)(struct nsproxy *nsproxy, struct ns_common *ns); 20 int (*install)(struct nsproxy *nsproxy, struct ns_common *ns);
21 struct user_namespace *(*owner)(struct ns_common *ns);
21}; 22};
22 23
23extern const struct proc_ns_operations netns_operations; 24extern const struct proc_ns_operations netns_operations;
diff --git a/include/linux/user_namespace.h b/include/linux/user_namespace.h
index 9217169c64cb..190cf0760815 100644
--- a/include/linux/user_namespace.h
+++ b/include/linux/user_namespace.h
@@ -73,6 +73,8 @@ extern ssize_t proc_setgroups_write(struct file *, const char __user *, size_t,
73extern int proc_setgroups_show(struct seq_file *m, void *v); 73extern int proc_setgroups_show(struct seq_file *m, void *v);
74extern bool userns_may_setgroups(const struct user_namespace *ns); 74extern bool userns_may_setgroups(const struct user_namespace *ns);
75extern bool current_in_userns(const struct user_namespace *target_ns); 75extern bool current_in_userns(const struct user_namespace *target_ns);
76
77struct ns_common *ns_get_owner(struct ns_common *ns);
76#else 78#else
77 79
78static inline struct user_namespace *get_user_ns(struct user_namespace *ns) 80static inline struct user_namespace *get_user_ns(struct user_namespace *ns)
@@ -106,6 +108,11 @@ static inline bool current_in_userns(const struct user_namespace *target_ns)
106{ 108{
107 return true; 109 return true;
108} 110}
111
112static inline struct ns_common *ns_get_owner(struct ns_common *ns)
113{
114 return ERR_PTR(-EPERM);
115}
109#endif 116#endif
110 117
111#endif /* _LINUX_USER_H */ 118#endif /* _LINUX_USER_H */
diff --git a/ipc/namespace.c b/ipc/namespace.c
index d87e6baa1323..578d93be619d 100644
--- a/ipc/namespace.c
+++ b/ipc/namespace.c
@@ -165,10 +165,16 @@ static int ipcns_install(struct nsproxy *nsproxy, struct ns_common *new)
165 return 0; 165 return 0;
166} 166}
167 167
168static struct user_namespace *ipcns_owner(struct ns_common *ns)
169{
170 return to_ipc_ns(ns)->user_ns;
171}
172
168const struct proc_ns_operations ipcns_operations = { 173const struct proc_ns_operations ipcns_operations = {
169 .name = "ipc", 174 .name = "ipc",
170 .type = CLONE_NEWIPC, 175 .type = CLONE_NEWIPC,
171 .get = ipcns_get, 176 .get = ipcns_get,
172 .put = ipcns_put, 177 .put = ipcns_put,
173 .install = ipcns_install, 178 .install = ipcns_install,
179 .owner = ipcns_owner,
174}; 180};
diff --git a/kernel/cgroup.c b/kernel/cgroup.c
index d1c51b7f5221..86b0e8b16426 100644
--- a/kernel/cgroup.c
+++ b/kernel/cgroup.c
@@ -6403,12 +6403,18 @@ static void cgroupns_put(struct ns_common *ns)
6403 put_cgroup_ns(to_cg_ns(ns)); 6403 put_cgroup_ns(to_cg_ns(ns));
6404} 6404}
6405 6405
6406static struct user_namespace *cgroupns_owner(struct ns_common *ns)
6407{
6408 return to_cg_ns(ns)->user_ns;
6409}
6410
6406const struct proc_ns_operations cgroupns_operations = { 6411const struct proc_ns_operations cgroupns_operations = {
6407 .name = "cgroup", 6412 .name = "cgroup",
6408 .type = CLONE_NEWCGROUP, 6413 .type = CLONE_NEWCGROUP,
6409 .get = cgroupns_get, 6414 .get = cgroupns_get,
6410 .put = cgroupns_put, 6415 .put = cgroupns_put,
6411 .install = cgroupns_install, 6416 .install = cgroupns_install,
6417 .owner = cgroupns_owner,
6412}; 6418};
6413 6419
6414static __init int cgroup_namespaces_init(void) 6420static __init int cgroup_namespaces_init(void)
diff --git a/kernel/pid_namespace.c b/kernel/pid_namespace.c
index a65ba137fd15..c02d744225e1 100644
--- a/kernel/pid_namespace.c
+++ b/kernel/pid_namespace.c
@@ -388,12 +388,18 @@ static int pidns_install(struct nsproxy *nsproxy, struct ns_common *ns)
388 return 0; 388 return 0;
389} 389}
390 390
391static struct user_namespace *pidns_owner(struct ns_common *ns)
392{
393 return to_pid_ns(ns)->user_ns;
394}
395
391const struct proc_ns_operations pidns_operations = { 396const struct proc_ns_operations pidns_operations = {
392 .name = "pid", 397 .name = "pid",
393 .type = CLONE_NEWPID, 398 .type = CLONE_NEWPID,
394 .get = pidns_get, 399 .get = pidns_get,
395 .put = pidns_put, 400 .put = pidns_put,
396 .install = pidns_install, 401 .install = pidns_install,
402 .owner = pidns_owner,
397}; 403};
398 404
399static __init int pid_namespaces_init(void) 405static __init int pid_namespaces_init(void)
diff --git a/kernel/user_namespace.c b/kernel/user_namespace.c
index 68f594212759..0ef683a03c20 100644
--- a/kernel/user_namespace.c
+++ b/kernel/user_namespace.c
@@ -1004,12 +1004,36 @@ static int userns_install(struct nsproxy *nsproxy, struct ns_common *ns)
1004 return commit_creds(cred); 1004 return commit_creds(cred);
1005} 1005}
1006 1006
1007struct ns_common *ns_get_owner(struct ns_common *ns)
1008{
1009 struct user_namespace *my_user_ns = current_user_ns();
1010 struct user_namespace *owner, *p;
1011
1012 /* See if the owner is in the current user namespace */
1013 owner = p = ns->ops->owner(ns);
1014 for (;;) {
1015 if (!p)
1016 return ERR_PTR(-EPERM);
1017 if (p == my_user_ns)
1018 break;
1019 p = p->parent;
1020 }
1021
1022 return &get_user_ns(owner)->ns;
1023}
1024
1025static struct user_namespace *userns_owner(struct ns_common *ns)
1026{
1027 return to_user_ns(ns)->parent;
1028}
1029
1007const struct proc_ns_operations userns_operations = { 1030const struct proc_ns_operations userns_operations = {
1008 .name = "user", 1031 .name = "user",
1009 .type = CLONE_NEWUSER, 1032 .type = CLONE_NEWUSER,
1010 .get = userns_get, 1033 .get = userns_get,
1011 .put = userns_put, 1034 .put = userns_put,
1012 .install = userns_install, 1035 .install = userns_install,
1036 .owner = userns_owner,
1013}; 1037};
1014 1038
1015static __init int user_namespaces_init(void) 1039static __init int user_namespaces_init(void)
diff --git a/kernel/utsname.c b/kernel/utsname.c
index 831ea7108232..e1211a8a5c18 100644
--- a/kernel/utsname.c
+++ b/kernel/utsname.c
@@ -130,10 +130,16 @@ static int utsns_install(struct nsproxy *nsproxy, struct ns_common *new)
130 return 0; 130 return 0;
131} 131}
132 132
133static struct user_namespace *utsns_owner(struct ns_common *ns)
134{
135 return to_uts_ns(ns)->user_ns;
136}
137
133const struct proc_ns_operations utsns_operations = { 138const struct proc_ns_operations utsns_operations = {
134 .name = "uts", 139 .name = "uts",
135 .type = CLONE_NEWUTS, 140 .type = CLONE_NEWUTS,
136 .get = utsns_get, 141 .get = utsns_get,
137 .put = utsns_put, 142 .put = utsns_put,
138 .install = utsns_install, 143 .install = utsns_install,
144 .owner = utsns_owner,
139}; 145};
diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c
index 2c2eb1b629b1..861efa34f08c 100644
--- a/net/core/net_namespace.c
+++ b/net/core/net_namespace.c
@@ -996,11 +996,17 @@ static int netns_install(struct nsproxy *nsproxy, struct ns_common *ns)
996 return 0; 996 return 0;
997} 997}
998 998
999static struct user_namespace *netns_owner(struct ns_common *ns)
1000{
1001 return to_net_ns(ns)->user_ns;
1002}
1003
999const struct proc_ns_operations netns_operations = { 1004const struct proc_ns_operations netns_operations = {
1000 .name = "net", 1005 .name = "net",
1001 .type = CLONE_NEWNET, 1006 .type = CLONE_NEWNET,
1002 .get = netns_get, 1007 .get = netns_get,
1003 .put = netns_put, 1008 .put = netns_put,
1004 .install = netns_install, 1009 .install = netns_install,
1010 .owner = netns_owner,
1005}; 1011};
1006#endif 1012#endif