File Index
Files and directories
Sign in
FILE

namespace.c

File preview with syntax highlighting.

linux-6.19.14/kernel/cgroup/namespace.c C
  1// SPDX-License-Identifier: GPL-2.0
  2#include "cgroup-internal.h"
  3
  4#include <linux/sched/task.h>
  5#include <linux/slab.h>
  6#include <linux/nsproxy.h>
  7#include <linux/proc_ns.h>
  8#include <linux/nstree.h>
  9
 10/* cgroup namespaces */
 11
 12static struct ucounts *inc_cgroup_namespaces(struct user_namespace *ns)
 13{
 14	return inc_ucount(ns, current_euid(), UCOUNT_CGROUP_NAMESPACES);
 15}
 16
 17static void dec_cgroup_namespaces(struct ucounts *ucounts)
 18{
 19	dec_ucount(ucounts, UCOUNT_CGROUP_NAMESPACES);
 20}
 21
 22static struct cgroup_namespace *alloc_cgroup_ns(void)
 23{
 24	struct cgroup_namespace *new_ns __free(kfree) = NULL;
 25	int ret;
 26
 27	new_ns = kzalloc(sizeof(struct cgroup_namespace), GFP_KERNEL_ACCOUNT);
 28	if (!new_ns)
 29		return ERR_PTR(-ENOMEM);
 30	ret = ns_common_init(new_ns);
 31	if (ret)
 32		return ERR_PTR(ret);
 33	return no_free_ptr(new_ns);
 34}
 35
 36void free_cgroup_ns(struct cgroup_namespace *ns)
 37{
 38	ns_tree_remove(ns);
 39	put_css_set(ns->root_cset);
 40	dec_cgroup_namespaces(ns->ucounts);
 41	put_user_ns(ns->user_ns);
 42	ns_common_free(ns);
 43	/* Concurrent nstree traversal depends on a grace period. */
 44	kfree_rcu(ns, ns.ns_rcu);
 45}
 46EXPORT_SYMBOL(free_cgroup_ns);
 47
 48struct cgroup_namespace *copy_cgroup_ns(u64 flags,
 49					struct user_namespace *user_ns,
 50					struct cgroup_namespace *old_ns)
 51{
 52	struct cgroup_namespace *new_ns;
 53	struct ucounts *ucounts;
 54	struct css_set *cset;
 55
 56	BUG_ON(!old_ns);
 57
 58	if (!(flags & CLONE_NEWCGROUP)) {
 59		get_cgroup_ns(old_ns);
 60		return old_ns;
 61	}
 62
 63	/* Allow only sysadmin to create cgroup namespace. */
 64	if (!ns_capable(user_ns, CAP_SYS_ADMIN))
 65		return ERR_PTR(-EPERM);
 66
 67	ucounts = inc_cgroup_namespaces(user_ns);
 68	if (!ucounts)
 69		return ERR_PTR(-ENOSPC);
 70
 71	/* It is not safe to take cgroup_mutex here */
 72	spin_lock_irq(&css_set_lock);
 73	cset = task_css_set(current);
 74	get_css_set(cset);
 75	spin_unlock_irq(&css_set_lock);
 76
 77	new_ns = alloc_cgroup_ns();
 78	if (IS_ERR(new_ns)) {
 79		put_css_set(cset);
 80		dec_cgroup_namespaces(ucounts);
 81		return new_ns;
 82	}
 83
 84	new_ns->user_ns = get_user_ns(user_ns);
 85	new_ns->ucounts = ucounts;
 86	new_ns->root_cset = cset;
 87
 88	ns_tree_add(new_ns);
 89	return new_ns;
 90}
 91
 92static int cgroupns_install(struct nsset *nsset, struct ns_common *ns)
 93{
 94	struct nsproxy *nsproxy = nsset->nsproxy;
 95	struct cgroup_namespace *cgroup_ns = to_cg_ns(ns);
 96
 97	if (!ns_capable(nsset->cred->user_ns, CAP_SYS_ADMIN) ||
 98	    !ns_capable(cgroup_ns->user_ns, CAP_SYS_ADMIN))
 99		return -EPERM;
100
101	/* Don't need to do anything if we are attaching to our own cgroupns. */
102	if (cgroup_ns == nsproxy->cgroup_ns)
103		return 0;
104
105	get_cgroup_ns(cgroup_ns);
106	put_cgroup_ns(nsproxy->cgroup_ns);
107	nsproxy->cgroup_ns = cgroup_ns;
108
109	return 0;
110}
111
112static struct ns_common *cgroupns_get(struct task_struct *task)
113{
114	struct cgroup_namespace *ns = NULL;
115	struct nsproxy *nsproxy;
116
117	task_lock(task);
118	nsproxy = task->nsproxy;
119	if (nsproxy) {
120		ns = nsproxy->cgroup_ns;
121		get_cgroup_ns(ns);
122	}
123	task_unlock(task);
124
125	return ns ? &ns->ns : NULL;
126}
127
128static void cgroupns_put(struct ns_common *ns)
129{
130	put_cgroup_ns(to_cg_ns(ns));
131}
132
133static struct user_namespace *cgroupns_owner(struct ns_common *ns)
134{
135	return to_cg_ns(ns)->user_ns;
136}
137
138const struct proc_ns_operations cgroupns_operations = {
139	.name		= "cgroup",
140	.get		= cgroupns_get,
141	.put		= cgroupns_put,
142	.install	= cgroupns_install,
143	.owner		= cgroupns_owner,
144};
~/ Read-only file preview.