diff options
-rw-r--r-- | fs/proc/namespaces.c | 3 | ||||
-rw-r--r-- | include/linux/cgroup.h | 49 | ||||
-rw-r--r-- | include/linux/nsproxy.h | 2 | ||||
-rw-r--r-- | include/linux/proc_ns.h | 4 | ||||
-rw-r--r-- | kernel/cgroup.c | 173 | ||||
-rw-r--r-- | kernel/cpuset.c | 8 | ||||
-rw-r--r-- | kernel/fork.c | 2 | ||||
-rw-r--r-- | kernel/nsproxy.c | 19 |
8 files changed, 250 insertions, 10 deletions
diff --git a/fs/proc/namespaces.c b/fs/proc/namespaces.c index 276f12431dbf..72cb26f85d58 100644 --- a/fs/proc/namespaces.c +++ b/fs/proc/namespaces.c | |||
@@ -28,6 +28,9 @@ static const struct proc_ns_operations *ns_entries[] = { | |||
28 | &userns_operations, | 28 | &userns_operations, |
29 | #endif | 29 | #endif |
30 | &mntns_operations, | 30 | &mntns_operations, |
31 | #ifdef CONFIG_CGROUPS | ||
32 | &cgroupns_operations, | ||
33 | #endif | ||
31 | }; | 34 | }; |
32 | 35 | ||
33 | static const char *proc_ns_get_link(struct dentry *dentry, | 36 | static const char *proc_ns_get_link(struct dentry *dentry, |
diff --git a/include/linux/cgroup.h b/include/linux/cgroup.h index 2162dca88dc0..a20320c666fd 100644 --- a/include/linux/cgroup.h +++ b/include/linux/cgroup.h | |||
@@ -17,6 +17,11 @@ | |||
17 | #include <linux/seq_file.h> | 17 | #include <linux/seq_file.h> |
18 | #include <linux/kernfs.h> | 18 | #include <linux/kernfs.h> |
19 | #include <linux/jump_label.h> | 19 | #include <linux/jump_label.h> |
20 | #include <linux/nsproxy.h> | ||
21 | #include <linux/types.h> | ||
22 | #include <linux/ns_common.h> | ||
23 | #include <linux/nsproxy.h> | ||
24 | #include <linux/user_namespace.h> | ||
20 | 25 | ||
21 | #include <linux/cgroup-defs.h> | 26 | #include <linux/cgroup-defs.h> |
22 | 27 | ||
@@ -611,4 +616,48 @@ static inline void cgroup_sk_free(struct sock_cgroup_data *skcd) {} | |||
611 | 616 | ||
612 | #endif /* CONFIG_CGROUP_DATA */ | 617 | #endif /* CONFIG_CGROUP_DATA */ |
613 | 618 | ||
619 | struct cgroup_namespace { | ||
620 | atomic_t count; | ||
621 | struct ns_common ns; | ||
622 | struct user_namespace *user_ns; | ||
623 | struct css_set *root_cset; | ||
624 | }; | ||
625 | |||
626 | extern struct cgroup_namespace init_cgroup_ns; | ||
627 | |||
628 | #ifdef CONFIG_CGROUPS | ||
629 | |||
630 | void free_cgroup_ns(struct cgroup_namespace *ns); | ||
631 | |||
632 | struct cgroup_namespace *copy_cgroup_ns(unsigned long flags, | ||
633 | struct user_namespace *user_ns, | ||
634 | struct cgroup_namespace *old_ns); | ||
635 | |||
636 | char *cgroup_path_ns(struct cgroup *cgrp, char *buf, size_t buflen, | ||
637 | struct cgroup_namespace *ns); | ||
638 | |||
639 | #else /* !CONFIG_CGROUPS */ | ||
640 | |||
641 | static inline void free_cgroup_ns(struct cgroup_namespace *ns) { } | ||
642 | static inline struct cgroup_namespace * | ||
643 | copy_cgroup_ns(unsigned long flags, struct user_namespace *user_ns, | ||
644 | struct cgroup_namespace *old_ns) | ||
645 | { | ||
646 | return old_ns; | ||
647 | } | ||
648 | |||
649 | #endif /* !CONFIG_CGROUPS */ | ||
650 | |||
651 | static inline void get_cgroup_ns(struct cgroup_namespace *ns) | ||
652 | { | ||
653 | if (ns) | ||
654 | atomic_inc(&ns->count); | ||
655 | } | ||
656 | |||
657 | static inline void put_cgroup_ns(struct cgroup_namespace *ns) | ||
658 | { | ||
659 | if (ns && atomic_dec_and_test(&ns->count)) | ||
660 | free_cgroup_ns(ns); | ||
661 | } | ||
662 | |||
614 | #endif /* _LINUX_CGROUP_H */ | 663 | #endif /* _LINUX_CGROUP_H */ |
diff --git a/include/linux/nsproxy.h b/include/linux/nsproxy.h index 35fa08fd7739..ac0d65bef5d0 100644 --- a/include/linux/nsproxy.h +++ b/include/linux/nsproxy.h | |||
@@ -8,6 +8,7 @@ struct mnt_namespace; | |||
8 | struct uts_namespace; | 8 | struct uts_namespace; |
9 | struct ipc_namespace; | 9 | struct ipc_namespace; |
10 | struct pid_namespace; | 10 | struct pid_namespace; |
11 | struct cgroup_namespace; | ||
11 | struct fs_struct; | 12 | struct fs_struct; |
12 | 13 | ||
13 | /* | 14 | /* |
@@ -33,6 +34,7 @@ struct nsproxy { | |||
33 | struct mnt_namespace *mnt_ns; | 34 | struct mnt_namespace *mnt_ns; |
34 | struct pid_namespace *pid_ns_for_children; | 35 | struct pid_namespace *pid_ns_for_children; |
35 | struct net *net_ns; | 36 | struct net *net_ns; |
37 | struct cgroup_namespace *cgroup_ns; | ||
36 | }; | 38 | }; |
37 | extern struct nsproxy init_nsproxy; | 39 | extern struct nsproxy init_nsproxy; |
38 | 40 | ||
diff --git a/include/linux/proc_ns.h b/include/linux/proc_ns.h index 42dfc615dbf8..de0e7719d4c5 100644 --- a/include/linux/proc_ns.h +++ b/include/linux/proc_ns.h | |||
@@ -9,6 +9,8 @@ | |||
9 | struct pid_namespace; | 9 | struct pid_namespace; |
10 | struct nsproxy; | 10 | struct nsproxy; |
11 | struct path; | 11 | struct path; |
12 | struct task_struct; | ||
13 | struct inode; | ||
12 | 14 | ||
13 | struct proc_ns_operations { | 15 | struct proc_ns_operations { |
14 | const char *name; | 16 | const char *name; |
@@ -24,6 +26,7 @@ extern const struct proc_ns_operations ipcns_operations; | |||
24 | extern const struct proc_ns_operations pidns_operations; | 26 | extern const struct proc_ns_operations pidns_operations; |
25 | extern const struct proc_ns_operations userns_operations; | 27 | extern const struct proc_ns_operations userns_operations; |
26 | extern const struct proc_ns_operations mntns_operations; | 28 | extern const struct proc_ns_operations mntns_operations; |
29 | extern const struct proc_ns_operations cgroupns_operations; | ||
27 | 30 | ||
28 | /* | 31 | /* |
29 | * We always define these enumerators | 32 | * We always define these enumerators |
@@ -34,6 +37,7 @@ enum { | |||
34 | PROC_UTS_INIT_INO = 0xEFFFFFFEU, | 37 | PROC_UTS_INIT_INO = 0xEFFFFFFEU, |
35 | PROC_USER_INIT_INO = 0xEFFFFFFDU, | 38 | PROC_USER_INIT_INO = 0xEFFFFFFDU, |
36 | PROC_PID_INIT_INO = 0xEFFFFFFCU, | 39 | PROC_PID_INIT_INO = 0xEFFFFFFCU, |
40 | PROC_CGROUP_INIT_INO = 0xEFFFFFFBU, | ||
37 | }; | 41 | }; |
38 | 42 | ||
39 | #ifdef CONFIG_PROC_FS | 43 | #ifdef CONFIG_PROC_FS |
diff --git a/kernel/cgroup.c b/kernel/cgroup.c index 7ad61915967f..b001c5d36bec 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c | |||
@@ -59,6 +59,9 @@ | |||
59 | #include <linux/delay.h> | 59 | #include <linux/delay.h> |
60 | #include <linux/atomic.h> | 60 | #include <linux/atomic.h> |
61 | #include <linux/cpuset.h> | 61 | #include <linux/cpuset.h> |
62 | #include <linux/proc_ns.h> | ||
63 | #include <linux/nsproxy.h> | ||
64 | #include <linux/proc_ns.h> | ||
62 | #include <net/sock.h> | 65 | #include <net/sock.h> |
63 | 66 | ||
64 | /* | 67 | /* |
@@ -212,6 +215,15 @@ static unsigned long have_fork_callback __read_mostly; | |||
212 | static unsigned long have_exit_callback __read_mostly; | 215 | static unsigned long have_exit_callback __read_mostly; |
213 | static unsigned long have_free_callback __read_mostly; | 216 | static unsigned long have_free_callback __read_mostly; |
214 | 217 | ||
218 | /* cgroup namespace for init task */ | ||
219 | struct cgroup_namespace init_cgroup_ns = { | ||
220 | .count = { .counter = 2, }, | ||
221 | .user_ns = &init_user_ns, | ||
222 | .ns.ops = &cgroupns_operations, | ||
223 | .ns.inum = PROC_CGROUP_INIT_INO, | ||
224 | .root_cset = &init_css_set, | ||
225 | }; | ||
226 | |||
215 | /* Ditto for the can_fork callback. */ | 227 | /* Ditto for the can_fork callback. */ |
216 | static unsigned long have_canfork_callback __read_mostly; | 228 | static unsigned long have_canfork_callback __read_mostly; |
217 | 229 | ||
@@ -2177,6 +2189,35 @@ static struct file_system_type cgroup2_fs_type = { | |||
2177 | .kill_sb = cgroup_kill_sb, | 2189 | .kill_sb = cgroup_kill_sb, |
2178 | }; | 2190 | }; |
2179 | 2191 | ||
2192 | static char *cgroup_path_ns_locked(struct cgroup *cgrp, char *buf, size_t buflen, | ||
2193 | struct cgroup_namespace *ns) | ||
2194 | { | ||
2195 | struct cgroup *root = cset_cgroup_from_root(ns->root_cset, cgrp->root); | ||
2196 | int ret; | ||
2197 | |||
2198 | ret = kernfs_path_from_node(cgrp->kn, root->kn, buf, buflen); | ||
2199 | if (ret < 0 || ret >= buflen) | ||
2200 | return NULL; | ||
2201 | return buf; | ||
2202 | } | ||
2203 | |||
2204 | char *cgroup_path_ns(struct cgroup *cgrp, char *buf, size_t buflen, | ||
2205 | struct cgroup_namespace *ns) | ||
2206 | { | ||
2207 | char *ret; | ||
2208 | |||
2209 | mutex_lock(&cgroup_mutex); | ||
2210 | spin_lock_bh(&css_set_lock); | ||
2211 | |||
2212 | ret = cgroup_path_ns_locked(cgrp, buf, buflen, ns); | ||
2213 | |||
2214 | spin_unlock_bh(&css_set_lock); | ||
2215 | mutex_unlock(&cgroup_mutex); | ||
2216 | |||
2217 | return ret; | ||
2218 | } | ||
2219 | EXPORT_SYMBOL_GPL(cgroup_path_ns); | ||
2220 | |||
2180 | /** | 2221 | /** |
2181 | * task_cgroup_path - cgroup path of a task in the first cgroup hierarchy | 2222 | * task_cgroup_path - cgroup path of a task in the first cgroup hierarchy |
2182 | * @task: target task | 2223 | * @task: target task |
@@ -2204,7 +2245,7 @@ char *task_cgroup_path(struct task_struct *task, char *buf, size_t buflen) | |||
2204 | 2245 | ||
2205 | if (root) { | 2246 | if (root) { |
2206 | cgrp = task_cgroup_from_root(task, root); | 2247 | cgrp = task_cgroup_from_root(task, root); |
2207 | path = cgroup_path(cgrp, buf, buflen); | 2248 | path = cgroup_path_ns_locked(cgrp, buf, buflen, &init_cgroup_ns); |
2208 | } else { | 2249 | } else { |
2209 | /* if no hierarchy exists, everyone is in "/" */ | 2250 | /* if no hierarchy exists, everyone is in "/" */ |
2210 | if (strlcpy(buf, "/", buflen) < buflen) | 2251 | if (strlcpy(buf, "/", buflen) < buflen) |
@@ -5297,6 +5338,8 @@ int __init cgroup_init(void) | |||
5297 | BUG_ON(cgroup_init_cftypes(NULL, cgroup_dfl_base_files)); | 5338 | BUG_ON(cgroup_init_cftypes(NULL, cgroup_dfl_base_files)); |
5298 | BUG_ON(cgroup_init_cftypes(NULL, cgroup_legacy_base_files)); | 5339 | BUG_ON(cgroup_init_cftypes(NULL, cgroup_legacy_base_files)); |
5299 | 5340 | ||
5341 | get_user_ns(init_cgroup_ns.user_ns); | ||
5342 | |||
5300 | mutex_lock(&cgroup_mutex); | 5343 | mutex_lock(&cgroup_mutex); |
5301 | 5344 | ||
5302 | /* Add init_css_set to the hash table */ | 5345 | /* Add init_css_set to the hash table */ |
@@ -5438,7 +5481,8 @@ int proc_cgroup_show(struct seq_file *m, struct pid_namespace *ns, | |||
5438 | * " (deleted)" is appended to the cgroup path. | 5481 | * " (deleted)" is appended to the cgroup path. |
5439 | */ | 5482 | */ |
5440 | if (cgroup_on_dfl(cgrp) || !(tsk->flags & PF_EXITING)) { | 5483 | if (cgroup_on_dfl(cgrp) || !(tsk->flags & PF_EXITING)) { |
5441 | path = cgroup_path(cgrp, buf, PATH_MAX); | 5484 | path = cgroup_path_ns_locked(cgrp, buf, PATH_MAX, |
5485 | current->nsproxy->cgroup_ns); | ||
5442 | if (!path) { | 5486 | if (!path) { |
5443 | retval = -ENAMETOOLONG; | 5487 | retval = -ENAMETOOLONG; |
5444 | goto out_unlock; | 5488 | goto out_unlock; |
@@ -5720,7 +5764,9 @@ static void cgroup_release_agent(struct work_struct *work) | |||
5720 | if (!pathbuf || !agentbuf) | 5764 | if (!pathbuf || !agentbuf) |
5721 | goto out; | 5765 | goto out; |
5722 | 5766 | ||
5723 | path = cgroup_path(cgrp, pathbuf, PATH_MAX); | 5767 | spin_lock_bh(&css_set_lock); |
5768 | path = cgroup_path_ns_locked(cgrp, pathbuf, PATH_MAX, &init_cgroup_ns); | ||
5769 | spin_unlock_bh(&css_set_lock); | ||
5724 | if (!path) | 5770 | if (!path) |
5725 | goto out; | 5771 | goto out; |
5726 | 5772 | ||
@@ -5931,6 +5977,127 @@ void cgroup_sk_free(struct sock_cgroup_data *skcd) | |||
5931 | 5977 | ||
5932 | #endif /* CONFIG_SOCK_CGROUP_DATA */ | 5978 | #endif /* CONFIG_SOCK_CGROUP_DATA */ |
5933 | 5979 | ||
5980 | /* cgroup namespaces */ | ||
5981 | |||
5982 | static struct cgroup_namespace *alloc_cgroup_ns(void) | ||
5983 | { | ||
5984 | struct cgroup_namespace *new_ns; | ||
5985 | int ret; | ||
5986 | |||
5987 | new_ns = kzalloc(sizeof(struct cgroup_namespace), GFP_KERNEL); | ||
5988 | if (!new_ns) | ||
5989 | return ERR_PTR(-ENOMEM); | ||
5990 | ret = ns_alloc_inum(&new_ns->ns); | ||
5991 | if (ret) { | ||
5992 | kfree(new_ns); | ||
5993 | return ERR_PTR(ret); | ||
5994 | } | ||
5995 | atomic_set(&new_ns->count, 1); | ||
5996 | new_ns->ns.ops = &cgroupns_operations; | ||
5997 | return new_ns; | ||
5998 | } | ||
5999 | |||
6000 | void free_cgroup_ns(struct cgroup_namespace *ns) | ||
6001 | { | ||
6002 | put_css_set(ns->root_cset); | ||
6003 | put_user_ns(ns->user_ns); | ||
6004 | ns_free_inum(&ns->ns); | ||
6005 | kfree(ns); | ||
6006 | } | ||
6007 | EXPORT_SYMBOL(free_cgroup_ns); | ||
6008 | |||
6009 | struct cgroup_namespace *copy_cgroup_ns(unsigned long flags, | ||
6010 | struct user_namespace *user_ns, | ||
6011 | struct cgroup_namespace *old_ns) | ||
6012 | { | ||
6013 | struct cgroup_namespace *new_ns = NULL; | ||
6014 | struct css_set *cset = NULL; | ||
6015 | int err; | ||
6016 | |||
6017 | BUG_ON(!old_ns); | ||
6018 | |||
6019 | if (!(flags & CLONE_NEWCGROUP)) { | ||
6020 | get_cgroup_ns(old_ns); | ||
6021 | return old_ns; | ||
6022 | } | ||
6023 | |||
6024 | /* Allow only sysadmin to create cgroup namespace. */ | ||
6025 | err = -EPERM; | ||
6026 | if (!ns_capable(user_ns, CAP_SYS_ADMIN)) | ||
6027 | goto err_out; | ||
6028 | |||
6029 | mutex_lock(&cgroup_mutex); | ||
6030 | spin_lock_bh(&css_set_lock); | ||
6031 | |||
6032 | cset = task_css_set(current); | ||
6033 | get_css_set(cset); | ||
6034 | |||
6035 | spin_unlock_bh(&css_set_lock); | ||
6036 | mutex_unlock(&cgroup_mutex); | ||
6037 | |||
6038 | err = -ENOMEM; | ||
6039 | new_ns = alloc_cgroup_ns(); | ||
6040 | if (!new_ns) | ||
6041 | goto err_out; | ||
6042 | |||
6043 | new_ns->user_ns = get_user_ns(user_ns); | ||
6044 | new_ns->root_cset = cset; | ||
6045 | |||
6046 | return new_ns; | ||
6047 | |||
6048 | err_out: | ||
6049 | if (cset) | ||
6050 | put_css_set(cset); | ||
6051 | kfree(new_ns); | ||
6052 | return ERR_PTR(err); | ||
6053 | } | ||
6054 | |||
6055 | static inline struct cgroup_namespace *to_cg_ns(struct ns_common *ns) | ||
6056 | { | ||
6057 | return container_of(ns, struct cgroup_namespace, ns); | ||
6058 | } | ||
6059 | |||
6060 | static int cgroupns_install(struct nsproxy *nsproxy, void *ns) | ||
6061 | { | ||
6062 | pr_info("setns not supported for cgroup namespace"); | ||
6063 | return -EINVAL; | ||
6064 | } | ||
6065 | |||
6066 | static struct ns_common *cgroupns_get(struct task_struct *task) | ||
6067 | { | ||
6068 | struct cgroup_namespace *ns = NULL; | ||
6069 | struct nsproxy *nsproxy; | ||
6070 | |||
6071 | task_lock(task); | ||
6072 | nsproxy = task->nsproxy; | ||
6073 | if (nsproxy) { | ||
6074 | ns = nsproxy->cgroup_ns; | ||
6075 | get_cgroup_ns(ns); | ||
6076 | } | ||
6077 | task_unlock(task); | ||
6078 | |||
6079 | return ns ? &ns->ns : NULL; | ||
6080 | } | ||
6081 | |||
6082 | static void cgroupns_put(struct ns_common *ns) | ||
6083 | { | ||
6084 | put_cgroup_ns(to_cg_ns(ns)); | ||
6085 | } | ||
6086 | |||
6087 | const struct proc_ns_operations cgroupns_operations = { | ||
6088 | .name = "cgroup", | ||
6089 | .type = CLONE_NEWCGROUP, | ||
6090 | .get = cgroupns_get, | ||
6091 | .put = cgroupns_put, | ||
6092 | .install = cgroupns_install, | ||
6093 | }; | ||
6094 | |||
6095 | static __init int cgroup_namespaces_init(void) | ||
6096 | { | ||
6097 | return 0; | ||
6098 | } | ||
6099 | subsys_initcall(cgroup_namespaces_init); | ||
6100 | |||
5934 | #ifdef CONFIG_CGROUP_DEBUG | 6101 | #ifdef CONFIG_CGROUP_DEBUG |
5935 | static struct cgroup_subsys_state * | 6102 | static struct cgroup_subsys_state * |
5936 | debug_css_alloc(struct cgroup_subsys_state *parent_css) | 6103 | debug_css_alloc(struct cgroup_subsys_state *parent_css) |
diff --git a/kernel/cpuset.c b/kernel/cpuset.c index 41989ab4db57..d393125b228c 100644 --- a/kernel/cpuset.c +++ b/kernel/cpuset.c | |||
@@ -2714,10 +2714,10 @@ int proc_cpuset_show(struct seq_file *m, struct pid_namespace *ns, | |||
2714 | goto out; | 2714 | goto out; |
2715 | 2715 | ||
2716 | retval = -ENAMETOOLONG; | 2716 | retval = -ENAMETOOLONG; |
2717 | rcu_read_lock(); | 2717 | css = task_get_css(tsk, cpuset_cgrp_id); |
2718 | css = task_css(tsk, cpuset_cgrp_id); | 2718 | p = cgroup_path_ns(css->cgroup, buf, PATH_MAX, |
2719 | p = cgroup_path(css->cgroup, buf, PATH_MAX); | 2719 | current->nsproxy->cgroup_ns); |
2720 | rcu_read_unlock(); | 2720 | css_put(css); |
2721 | if (!p) | 2721 | if (!p) |
2722 | goto out_free; | 2722 | goto out_free; |
2723 | seq_puts(m, p); | 2723 | seq_puts(m, p); |
diff --git a/kernel/fork.c b/kernel/fork.c index 2e391c754ae7..6611a6267949 100644 --- a/kernel/fork.c +++ b/kernel/fork.c | |||
@@ -1884,7 +1884,7 @@ static int check_unshare_flags(unsigned long unshare_flags) | |||
1884 | if (unshare_flags & ~(CLONE_THREAD|CLONE_FS|CLONE_NEWNS|CLONE_SIGHAND| | 1884 | if (unshare_flags & ~(CLONE_THREAD|CLONE_FS|CLONE_NEWNS|CLONE_SIGHAND| |
1885 | CLONE_VM|CLONE_FILES|CLONE_SYSVSEM| | 1885 | CLONE_VM|CLONE_FILES|CLONE_SYSVSEM| |
1886 | CLONE_NEWUTS|CLONE_NEWIPC|CLONE_NEWNET| | 1886 | CLONE_NEWUTS|CLONE_NEWIPC|CLONE_NEWNET| |
1887 | CLONE_NEWUSER|CLONE_NEWPID)) | 1887 | CLONE_NEWUSER|CLONE_NEWPID|CLONE_NEWCGROUP)) |
1888 | return -EINVAL; | 1888 | return -EINVAL; |
1889 | /* | 1889 | /* |
1890 | * Not implemented, but pretend it works if there is nothing | 1890 | * Not implemented, but pretend it works if there is nothing |
diff --git a/kernel/nsproxy.c b/kernel/nsproxy.c index 49746c81ad8d..782102e59eed 100644 --- a/kernel/nsproxy.c +++ b/kernel/nsproxy.c | |||
@@ -25,6 +25,7 @@ | |||
25 | #include <linux/proc_ns.h> | 25 | #include <linux/proc_ns.h> |
26 | #include <linux/file.h> | 26 | #include <linux/file.h> |
27 | #include <linux/syscalls.h> | 27 | #include <linux/syscalls.h> |
28 | #include <linux/cgroup.h> | ||
28 | 29 | ||
29 | static struct kmem_cache *nsproxy_cachep; | 30 | static struct kmem_cache *nsproxy_cachep; |
30 | 31 | ||
@@ -39,6 +40,9 @@ struct nsproxy init_nsproxy = { | |||
39 | #ifdef CONFIG_NET | 40 | #ifdef CONFIG_NET |
40 | .net_ns = &init_net, | 41 | .net_ns = &init_net, |
41 | #endif | 42 | #endif |
43 | #ifdef CONFIG_CGROUPS | ||
44 | .cgroup_ns = &init_cgroup_ns, | ||
45 | #endif | ||
42 | }; | 46 | }; |
43 | 47 | ||
44 | static inline struct nsproxy *create_nsproxy(void) | 48 | static inline struct nsproxy *create_nsproxy(void) |
@@ -92,6 +96,13 @@ static struct nsproxy *create_new_namespaces(unsigned long flags, | |||
92 | goto out_pid; | 96 | goto out_pid; |
93 | } | 97 | } |
94 | 98 | ||
99 | new_nsp->cgroup_ns = copy_cgroup_ns(flags, user_ns, | ||
100 | tsk->nsproxy->cgroup_ns); | ||
101 | if (IS_ERR(new_nsp->cgroup_ns)) { | ||
102 | err = PTR_ERR(new_nsp->cgroup_ns); | ||
103 | goto out_cgroup; | ||
104 | } | ||
105 | |||
95 | new_nsp->net_ns = copy_net_ns(flags, user_ns, tsk->nsproxy->net_ns); | 106 | new_nsp->net_ns = copy_net_ns(flags, user_ns, tsk->nsproxy->net_ns); |
96 | if (IS_ERR(new_nsp->net_ns)) { | 107 | if (IS_ERR(new_nsp->net_ns)) { |
97 | err = PTR_ERR(new_nsp->net_ns); | 108 | err = PTR_ERR(new_nsp->net_ns); |
@@ -101,6 +112,8 @@ static struct nsproxy *create_new_namespaces(unsigned long flags, | |||
101 | return new_nsp; | 112 | return new_nsp; |
102 | 113 | ||
103 | out_net: | 114 | out_net: |
115 | put_cgroup_ns(new_nsp->cgroup_ns); | ||
116 | out_cgroup: | ||
104 | if (new_nsp->pid_ns_for_children) | 117 | if (new_nsp->pid_ns_for_children) |
105 | put_pid_ns(new_nsp->pid_ns_for_children); | 118 | put_pid_ns(new_nsp->pid_ns_for_children); |
106 | out_pid: | 119 | out_pid: |
@@ -128,7 +141,8 @@ int copy_namespaces(unsigned long flags, struct task_struct *tsk) | |||
128 | struct nsproxy *new_ns; | 141 | struct nsproxy *new_ns; |
129 | 142 | ||
130 | if (likely(!(flags & (CLONE_NEWNS | CLONE_NEWUTS | CLONE_NEWIPC | | 143 | if (likely(!(flags & (CLONE_NEWNS | CLONE_NEWUTS | CLONE_NEWIPC | |
131 | CLONE_NEWPID | CLONE_NEWNET)))) { | 144 | CLONE_NEWPID | CLONE_NEWNET | |
145 | CLONE_NEWCGROUP)))) { | ||
132 | get_nsproxy(old_ns); | 146 | get_nsproxy(old_ns); |
133 | return 0; | 147 | return 0; |
134 | } | 148 | } |
@@ -165,6 +179,7 @@ void free_nsproxy(struct nsproxy *ns) | |||
165 | put_ipc_ns(ns->ipc_ns); | 179 | put_ipc_ns(ns->ipc_ns); |
166 | if (ns->pid_ns_for_children) | 180 | if (ns->pid_ns_for_children) |
167 | put_pid_ns(ns->pid_ns_for_children); | 181 | put_pid_ns(ns->pid_ns_for_children); |
182 | put_cgroup_ns(ns->cgroup_ns); | ||
168 | put_net(ns->net_ns); | 183 | put_net(ns->net_ns); |
169 | kmem_cache_free(nsproxy_cachep, ns); | 184 | kmem_cache_free(nsproxy_cachep, ns); |
170 | } | 185 | } |
@@ -180,7 +195,7 @@ int unshare_nsproxy_namespaces(unsigned long unshare_flags, | |||
180 | int err = 0; | 195 | int err = 0; |
181 | 196 | ||
182 | if (!(unshare_flags & (CLONE_NEWNS | CLONE_NEWUTS | CLONE_NEWIPC | | 197 | if (!(unshare_flags & (CLONE_NEWNS | CLONE_NEWUTS | CLONE_NEWIPC | |
183 | CLONE_NEWNET | CLONE_NEWPID))) | 198 | CLONE_NEWNET | CLONE_NEWPID | CLONE_NEWCGROUP))) |
184 | return 0; | 199 | return 0; |
185 | 200 | ||
186 | user_ns = new_cred ? new_cred->user_ns : current_user_ns(); | 201 | user_ns = new_cred ? new_cred->user_ns : current_user_ns(); |