|
@@ -718,7 +718,7 @@ static unsigned long css_set_hash(struct cgroup_subsys_state *css[])
|
|
|
return key;
|
|
|
}
|
|
|
|
|
|
-static void put_css_set_locked(struct css_set *cset)
|
|
|
+void put_css_set_locked(struct css_set *cset)
|
|
|
{
|
|
|
struct cgrp_cset_link *link, *tmp_link;
|
|
|
struct cgroup_subsys *ss;
|
|
@@ -748,31 +748,6 @@ static void put_css_set_locked(struct css_set *cset)
|
|
|
kfree_rcu(cset, rcu_head);
|
|
|
}
|
|
|
|
|
|
-static void put_css_set(struct css_set *cset)
|
|
|
-{
|
|
|
- unsigned long flags;
|
|
|
-
|
|
|
- /*
|
|
|
- * Ensure that the refcount doesn't hit zero while any readers
|
|
|
- * can see it. Similar to atomic_dec_and_lock(), but for an
|
|
|
- * rwlock
|
|
|
- */
|
|
|
- if (atomic_add_unless(&cset->refcount, -1, 1))
|
|
|
- return;
|
|
|
-
|
|
|
- spin_lock_irqsave(&css_set_lock, flags);
|
|
|
- put_css_set_locked(cset);
|
|
|
- spin_unlock_irqrestore(&css_set_lock, flags);
|
|
|
-}
|
|
|
-
|
|
|
-/*
|
|
|
- * refcounted get/put for css_set objects
|
|
|
- */
|
|
|
-static inline void get_css_set(struct css_set *cset)
|
|
|
-{
|
|
|
- atomic_inc(&cset->refcount);
|
|
|
-}
|
|
|
-
|
|
|
/**
|
|
|
* compare_css_sets - helper function for find_existing_css_set().
|
|
|
* @cset: candidate css_set being tested
|
|
@@ -5109,154 +5084,6 @@ void cgroup_sk_free(struct sock_cgroup_data *skcd)
|
|
|
|
|
|
#endif /* CONFIG_SOCK_CGROUP_DATA */
|
|
|
|
|
|
-/* cgroup namespaces */
|
|
|
-
|
|
|
-static struct ucounts *inc_cgroup_namespaces(struct user_namespace *ns)
|
|
|
-{
|
|
|
- return inc_ucount(ns, current_euid(), UCOUNT_CGROUP_NAMESPACES);
|
|
|
-}
|
|
|
-
|
|
|
-static void dec_cgroup_namespaces(struct ucounts *ucounts)
|
|
|
-{
|
|
|
- dec_ucount(ucounts, UCOUNT_CGROUP_NAMESPACES);
|
|
|
-}
|
|
|
-
|
|
|
-static struct cgroup_namespace *alloc_cgroup_ns(void)
|
|
|
-{
|
|
|
- struct cgroup_namespace *new_ns;
|
|
|
- int ret;
|
|
|
-
|
|
|
- new_ns = kzalloc(sizeof(struct cgroup_namespace), GFP_KERNEL);
|
|
|
- if (!new_ns)
|
|
|
- return ERR_PTR(-ENOMEM);
|
|
|
- ret = ns_alloc_inum(&new_ns->ns);
|
|
|
- if (ret) {
|
|
|
- kfree(new_ns);
|
|
|
- return ERR_PTR(ret);
|
|
|
- }
|
|
|
- atomic_set(&new_ns->count, 1);
|
|
|
- new_ns->ns.ops = &cgroupns_operations;
|
|
|
- return new_ns;
|
|
|
-}
|
|
|
-
|
|
|
-void free_cgroup_ns(struct cgroup_namespace *ns)
|
|
|
-{
|
|
|
- put_css_set(ns->root_cset);
|
|
|
- dec_cgroup_namespaces(ns->ucounts);
|
|
|
- put_user_ns(ns->user_ns);
|
|
|
- ns_free_inum(&ns->ns);
|
|
|
- kfree(ns);
|
|
|
-}
|
|
|
-EXPORT_SYMBOL(free_cgroup_ns);
|
|
|
-
|
|
|
-struct cgroup_namespace *copy_cgroup_ns(unsigned long flags,
|
|
|
- struct user_namespace *user_ns,
|
|
|
- struct cgroup_namespace *old_ns)
|
|
|
-{
|
|
|
- struct cgroup_namespace *new_ns;
|
|
|
- struct ucounts *ucounts;
|
|
|
- struct css_set *cset;
|
|
|
-
|
|
|
- BUG_ON(!old_ns);
|
|
|
-
|
|
|
- if (!(flags & CLONE_NEWCGROUP)) {
|
|
|
- get_cgroup_ns(old_ns);
|
|
|
- return old_ns;
|
|
|
- }
|
|
|
-
|
|
|
- /* Allow only sysadmin to create cgroup namespace. */
|
|
|
- if (!ns_capable(user_ns, CAP_SYS_ADMIN))
|
|
|
- return ERR_PTR(-EPERM);
|
|
|
-
|
|
|
- ucounts = inc_cgroup_namespaces(user_ns);
|
|
|
- if (!ucounts)
|
|
|
- return ERR_PTR(-ENOSPC);
|
|
|
-
|
|
|
- /* It is not safe to take cgroup_mutex here */
|
|
|
- spin_lock_irq(&css_set_lock);
|
|
|
- cset = task_css_set(current);
|
|
|
- get_css_set(cset);
|
|
|
- spin_unlock_irq(&css_set_lock);
|
|
|
-
|
|
|
- new_ns = alloc_cgroup_ns();
|
|
|
- if (IS_ERR(new_ns)) {
|
|
|
- put_css_set(cset);
|
|
|
- dec_cgroup_namespaces(ucounts);
|
|
|
- return new_ns;
|
|
|
- }
|
|
|
-
|
|
|
- new_ns->user_ns = get_user_ns(user_ns);
|
|
|
- new_ns->ucounts = ucounts;
|
|
|
- new_ns->root_cset = cset;
|
|
|
-
|
|
|
- return new_ns;
|
|
|
-}
|
|
|
-
|
|
|
-static inline struct cgroup_namespace *to_cg_ns(struct ns_common *ns)
|
|
|
-{
|
|
|
- return container_of(ns, struct cgroup_namespace, ns);
|
|
|
-}
|
|
|
-
|
|
|
-static int cgroupns_install(struct nsproxy *nsproxy, struct ns_common *ns)
|
|
|
-{
|
|
|
- struct cgroup_namespace *cgroup_ns = to_cg_ns(ns);
|
|
|
-
|
|
|
- if (!ns_capable(current_user_ns(), CAP_SYS_ADMIN) ||
|
|
|
- !ns_capable(cgroup_ns->user_ns, CAP_SYS_ADMIN))
|
|
|
- return -EPERM;
|
|
|
-
|
|
|
- /* Don't need to do anything if we are attaching to our own cgroupns. */
|
|
|
- if (cgroup_ns == nsproxy->cgroup_ns)
|
|
|
- return 0;
|
|
|
-
|
|
|
- get_cgroup_ns(cgroup_ns);
|
|
|
- put_cgroup_ns(nsproxy->cgroup_ns);
|
|
|
- nsproxy->cgroup_ns = cgroup_ns;
|
|
|
-
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-static struct ns_common *cgroupns_get(struct task_struct *task)
|
|
|
-{
|
|
|
- struct cgroup_namespace *ns = NULL;
|
|
|
- struct nsproxy *nsproxy;
|
|
|
-
|
|
|
- task_lock(task);
|
|
|
- nsproxy = task->nsproxy;
|
|
|
- if (nsproxy) {
|
|
|
- ns = nsproxy->cgroup_ns;
|
|
|
- get_cgroup_ns(ns);
|
|
|
- }
|
|
|
- task_unlock(task);
|
|
|
-
|
|
|
- return ns ? &ns->ns : NULL;
|
|
|
-}
|
|
|
-
|
|
|
-static void cgroupns_put(struct ns_common *ns)
|
|
|
-{
|
|
|
- put_cgroup_ns(to_cg_ns(ns));
|
|
|
-}
|
|
|
-
|
|
|
-static struct user_namespace *cgroupns_owner(struct ns_common *ns)
|
|
|
-{
|
|
|
- return to_cg_ns(ns)->user_ns;
|
|
|
-}
|
|
|
-
|
|
|
-const struct proc_ns_operations cgroupns_operations = {
|
|
|
- .name = "cgroup",
|
|
|
- .type = CLONE_NEWCGROUP,
|
|
|
- .get = cgroupns_get,
|
|
|
- .put = cgroupns_put,
|
|
|
- .install = cgroupns_install,
|
|
|
- .owner = cgroupns_owner,
|
|
|
-};
|
|
|
-
|
|
|
-static __init int cgroup_namespaces_init(void)
|
|
|
-{
|
|
|
- return 0;
|
|
|
-}
|
|
|
-subsys_initcall(cgroup_namespaces_init);
|
|
|
-
|
|
|
#ifdef CONFIG_CGROUP_BPF
|
|
|
void cgroup_bpf_update(struct cgroup *cgrp,
|
|
|
struct bpf_prog *prog,
|