|
59 | 59 | #include <linux/delay.h>
|
60 | 60 | #include <linux/atomic.h>
|
61 | 61 | #include <linux/cpuset.h>
|
| 62 | +#include <linux/proc_ns.h> |
| 63 | +#include <linux/nsproxy.h> |
| 64 | +#include <linux/proc_ns.h> |
62 | 65 | #include <net/sock.h>
|
63 | 66 |
|
64 | 67 | /*
|
@@ -212,6 +215,15 @@ static unsigned long have_fork_callback __read_mostly;
|
212 | 215 | static unsigned long have_exit_callback __read_mostly;
|
213 | 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 | 227 | /* Ditto for the can_fork callback. */
|
216 | 228 | static unsigned long have_canfork_callback __read_mostly;
|
217 | 229 |
|
@@ -2177,6 +2189,35 @@ static struct file_system_type cgroup2_fs_type = {
|
2177 | 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 | 2222 | * task_cgroup_path - cgroup path of a task in the first cgroup hierarchy
|
2182 | 2223 | * @task: target task
|
@@ -2204,7 +2245,7 @@ char *task_cgroup_path(struct task_struct *task, char *buf, size_t buflen)
|
2204 | 2245 |
|
2205 | 2246 | if (root) {
|
2206 | 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 | 2249 | } else {
|
2209 | 2250 | /* if no hierarchy exists, everyone is in "/" */
|
2210 | 2251 | if (strlcpy(buf, "/", buflen) < buflen)
|
@@ -5297,6 +5338,8 @@ int __init cgroup_init(void)
|
5297 | 5338 | BUG_ON(cgroup_init_cftypes(NULL, cgroup_dfl_base_files));
|
5298 | 5339 | BUG_ON(cgroup_init_cftypes(NULL, cgroup_legacy_base_files));
|
5299 | 5340 |
|
| 5341 | + get_user_ns(init_cgroup_ns.user_ns); |
| 5342 | + |
5300 | 5343 | mutex_lock(&cgroup_mutex);
|
5301 | 5344 |
|
5302 | 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 | 5481 | * " (deleted)" is appended to the cgroup path.
|
5439 | 5482 | */
|
5440 | 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 | 5486 | if (!path) {
|
5443 | 5487 | retval = -ENAMETOOLONG;
|
5444 | 5488 | goto out_unlock;
|
@@ -5720,7 +5764,9 @@ static void cgroup_release_agent(struct work_struct *work)
|
5720 | 5764 | if (!pathbuf || !agentbuf)
|
5721 | 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 | 5770 | if (!path)
|
5725 | 5771 | goto out;
|
5726 | 5772 |
|
@@ -5931,6 +5977,127 @@ void cgroup_sk_free(struct sock_cgroup_data *skcd)
|
5931 | 5977 |
|
5932 | 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 | 6101 | #ifdef CONFIG_CGROUP_DEBUG
|
5935 | 6102 | static struct cgroup_subsys_state *
|
5936 | 6103 | debug_css_alloc(struct cgroup_subsys_state *parent_css)
|
|
0 commit comments