diff options
author | Andrey Vagin <avagin@openvz.org> | 2016-09-06 03:47:13 -0400 |
---|---|---|
committer | Eric W. Biederman <ebiederm@xmission.com> | 2016-09-22 20:59:39 -0400 |
commit | bcac25a58bfc6bd79191ac5d7afb49bea96da8c9 (patch) | |
tree | 28a8ae71b2939267deba0807bcbbed28e77470c0 | |
parent | 29b4817d4018df78086157ea3a55c1d9424a7cfc (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.c | 6 | ||||
-rw-r--r-- | include/linux/proc_ns.h | 1 | ||||
-rw-r--r-- | include/linux/user_namespace.h | 7 | ||||
-rw-r--r-- | ipc/namespace.c | 6 | ||||
-rw-r--r-- | kernel/cgroup.c | 6 | ||||
-rw-r--r-- | kernel/pid_namespace.c | 6 | ||||
-rw-r--r-- | kernel/user_namespace.c | 24 | ||||
-rw-r--r-- | kernel/utsname.c | 6 | ||||
-rw-r--r-- | net/core/net_namespace.c | 6 |
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 | ||
3351 | static struct user_namespace *mntns_owner(struct ns_common *ns) | ||
3352 | { | ||
3353 | return to_mnt_ns(ns)->user_ns; | ||
3354 | } | ||
3355 | |||
3351 | const struct proc_ns_operations mntns_operations = { | 3356 | const 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 | ||
23 | extern const struct proc_ns_operations netns_operations; | 24 | extern 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, | |||
73 | extern int proc_setgroups_show(struct seq_file *m, void *v); | 73 | extern int proc_setgroups_show(struct seq_file *m, void *v); |
74 | extern bool userns_may_setgroups(const struct user_namespace *ns); | 74 | extern bool userns_may_setgroups(const struct user_namespace *ns); |
75 | extern bool current_in_userns(const struct user_namespace *target_ns); | 75 | extern bool current_in_userns(const struct user_namespace *target_ns); |
76 | |||
77 | struct ns_common *ns_get_owner(struct ns_common *ns); | ||
76 | #else | 78 | #else |
77 | 79 | ||
78 | static inline struct user_namespace *get_user_ns(struct user_namespace *ns) | 80 | static 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 | |||
112 | static 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 | ||
168 | static struct user_namespace *ipcns_owner(struct ns_common *ns) | ||
169 | { | ||
170 | return to_ipc_ns(ns)->user_ns; | ||
171 | } | ||
172 | |||
168 | const struct proc_ns_operations ipcns_operations = { | 173 | const 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 | ||
6406 | static struct user_namespace *cgroupns_owner(struct ns_common *ns) | ||
6407 | { | ||
6408 | return to_cg_ns(ns)->user_ns; | ||
6409 | } | ||
6410 | |||
6406 | const struct proc_ns_operations cgroupns_operations = { | 6411 | const 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 | ||
6414 | static __init int cgroup_namespaces_init(void) | 6420 | static __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 | ||
391 | static struct user_namespace *pidns_owner(struct ns_common *ns) | ||
392 | { | ||
393 | return to_pid_ns(ns)->user_ns; | ||
394 | } | ||
395 | |||
391 | const struct proc_ns_operations pidns_operations = { | 396 | const 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 | ||
399 | static __init int pid_namespaces_init(void) | 405 | static __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 | ||
1007 | struct 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 | |||
1025 | static struct user_namespace *userns_owner(struct ns_common *ns) | ||
1026 | { | ||
1027 | return to_user_ns(ns)->parent; | ||
1028 | } | ||
1029 | |||
1007 | const struct proc_ns_operations userns_operations = { | 1030 | const 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 | ||
1015 | static __init int user_namespaces_init(void) | 1039 | static __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 | ||
133 | static struct user_namespace *utsns_owner(struct ns_common *ns) | ||
134 | { | ||
135 | return to_uts_ns(ns)->user_ns; | ||
136 | } | ||
137 | |||
133 | const struct proc_ns_operations utsns_operations = { | 138 | const 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 | ||
999 | static struct user_namespace *netns_owner(struct ns_common *ns) | ||
1000 | { | ||
1001 | return to_net_ns(ns)->user_ns; | ||
1002 | } | ||
1003 | |||
999 | const struct proc_ns_operations netns_operations = { | 1004 | const 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 |