summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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();