summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAditya Kali <adityakali@google.com>2016-01-29 03:54:06 -0500
committerTejun Heo <tj@kernel.org>2016-02-16 13:04:58 -0500
commita79a908fd2b080977b45bf103184b81c9d11ad07 (patch)
treefbfb2423937d1ff6ff72e5ca9fa852b0c8d7da98
parent5e2bec7c2248ae27c5b16cd97215ae05c1d39179 (diff)
cgroup: introduce cgroup namespaces
Introduce the ability to create new cgroup namespace. The newly created cgroup namespace remembers the cgroup of the process at the point of creation of the cgroup namespace (referred as cgroupns-root). The main purpose of cgroup namespace is to virtualize the contents of /proc/self/cgroup file. Processes inside a cgroup namespace are only able to see paths relative to their namespace root (unless they are moved outside of their cgroupns-root, at which point they will see a relative path from their cgroupns-root). For a correctly setup container this enables container-tools (like libcontainer, lxc, lmctfy, etc.) to create completely virtualized containers without leaking system level cgroup hierarchy to the task. This patch only implements the 'unshare' part of the cgroupns. Signed-off-by: Aditya Kali <adityakali@google.com> Signed-off-by: Serge Hallyn <serge.hallyn@canonical.com> Signed-off-by: Tejun Heo <tj@kernel.org>
-rw-r--r--fs/proc/namespaces.c3
-rw-r--r--include/linux/cgroup.h49
-rw-r--r--include/linux/nsproxy.h2
-rw-r--r--include/linux/proc_ns.h4
-rw-r--r--kernel/cgroup.c173
-rw-r--r--kernel/cpuset.c8
-rw-r--r--kernel/fork.c2
-rw-r--r--kernel/nsproxy.c19
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
33static const char *proc_ns_get_link(struct dentry *dentry, 36static 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
619struct 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
626extern struct cgroup_namespace init_cgroup_ns;
627
628#ifdef CONFIG_CGROUPS
629
630void free_cgroup_ns(struct cgroup_namespace *ns);
631
632struct cgroup_namespace *copy_cgroup_ns(unsigned long flags,
633 struct user_namespace *user_ns,
634 struct cgroup_namespace *old_ns);
635
636char *cgroup_path_ns(struct cgroup *cgrp, char *buf, size_t buflen,
637 struct cgroup_namespace *ns);
638
639#else /* !CONFIG_CGROUPS */
640
641static inline void free_cgroup_ns(struct cgroup_namespace *ns) { }
642static inline struct cgroup_namespace *
643copy_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
651static inline void get_cgroup_ns(struct cgroup_namespace *ns)
652{
653 if (ns)
654 atomic_inc(&ns->count);
655}
656
657static 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;
8struct uts_namespace; 8struct uts_namespace;
9struct ipc_namespace; 9struct ipc_namespace;
10struct pid_namespace; 10struct pid_namespace;
11struct cgroup_namespace;
11struct fs_struct; 12struct 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};
37extern struct nsproxy init_nsproxy; 39extern 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 @@
9struct pid_namespace; 9struct pid_namespace;
10struct nsproxy; 10struct nsproxy;
11struct path; 11struct path;
12struct task_struct;
13struct inode;
12 14
13struct proc_ns_operations { 15struct proc_ns_operations {
14 const char *name; 16 const char *name;
@@ -24,6 +26,7 @@ extern const struct proc_ns_operations ipcns_operations;
24extern const struct proc_ns_operations pidns_operations; 26extern const struct proc_ns_operations pidns_operations;
25extern const struct proc_ns_operations userns_operations; 27extern const struct proc_ns_operations userns_operations;
26extern const struct proc_ns_operations mntns_operations; 28extern const struct proc_ns_operations mntns_operations;
29extern 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;
212static unsigned long have_exit_callback __read_mostly; 215static unsigned long have_exit_callback __read_mostly;
213static unsigned long have_free_callback __read_mostly; 216static unsigned long have_free_callback __read_mostly;
214 217
218/* cgroup namespace for init task */
219struct 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. */
216static unsigned long have_canfork_callback __read_mostly; 228static 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
2192static 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
2204char *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}
2219EXPORT_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
5982static 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
6000void 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}
6007EXPORT_SYMBOL(free_cgroup_ns);
6008
6009struct 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
6048err_out:
6049 if (cset)
6050 put_css_set(cset);
6051 kfree(new_ns);
6052 return ERR_PTR(err);
6053}
6054
6055static inline struct cgroup_namespace *to_cg_ns(struct ns_common *ns)
6056{
6057 return container_of(ns, struct cgroup_namespace, ns);
6058}
6059
6060static int cgroupns_install(struct nsproxy *nsproxy, void *ns)
6061{
6062 pr_info("setns not supported for cgroup namespace");
6063 return -EINVAL;
6064}
6065
6066static 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
6082static void cgroupns_put(struct ns_common *ns)
6083{
6084 put_cgroup_ns(to_cg_ns(ns));
6085}
6086
6087const 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
6095static __init int cgroup_namespaces_init(void)
6096{
6097 return 0;
6098}
6099subsys_initcall(cgroup_namespaces_init);
6100
5934#ifdef CONFIG_CGROUP_DEBUG 6101#ifdef CONFIG_CGROUP_DEBUG
5935static struct cgroup_subsys_state * 6102static struct cgroup_subsys_state *
5936debug_css_alloc(struct cgroup_subsys_state *parent_css) 6103debug_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
29static struct kmem_cache *nsproxy_cachep; 30static 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
44static inline struct nsproxy *create_nsproxy(void) 48static 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
103out_net: 114out_net:
115 put_cgroup_ns(new_nsp->cgroup_ns);
116out_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);
106out_pid: 119out_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();