Something went wrong. Try again.
Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145// SPDX-License-Identifier: GPL-2.0#include "cgroup-internal.h"
#include <linux/sched/task.h>#include <linux/slab.h>#include <linux/nsproxy.h>#include <linux/proc_ns.h>#include <linux/nstree.h>
/* 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 __free(kfree) = NULL; int ret;
new_ns = kzalloc_obj(struct cgroup_namespace, GFP_KERNEL_ACCOUNT); if (!new_ns) return ERR_PTR(-ENOMEM); ret = ns_common_init(new_ns); if (ret) return ERR_PTR(ret); return no_free_ptr(new_ns);}
void free_cgroup_ns(struct cgroup_namespace *ns){ ns_tree_remove(ns); put_css_set(ns->root_cset); dec_cgroup_namespaces(ns->ucounts); put_user_ns(ns->user_ns); ns_common_free(ns); /* Concurrent nstree traversal depends on a grace period. */ kfree_rcu(ns, ns.ns_rcu);}EXPORT_SYMBOL(free_cgroup_ns);
struct cgroup_namespace *copy_cgroup_ns(u64 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;
ns_tree_add(new_ns); return new_ns;}
static int cgroupns_install(struct nsset *nsset, struct ns_common *ns){ struct nsproxy *nsproxy = nsset->nsproxy; struct cgroup_namespace *cgroup_ns = to_cg_ns(ns);
if (!ns_capable(nsset->cred->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", .get = cgroupns_get, .put = cgroupns_put, .install = cgroupns_install, .owner = cgroupns_owner,};