1 // SPDX-License-Identifier: GPL-2.0
2 #include "cgroup-internal.h"
4 #include <linux/sched/task.h>
5 #include <linux/slab.h>
6 #include <linux/nsproxy.h>
7 #include <linux/proc_ns.h>
10 /* cgroup namespaces */
12 static struct ucounts
*inc_cgroup_namespaces(struct user_namespace
*ns
)
14 return inc_ucount(ns
, current_euid(), UCOUNT_CGROUP_NAMESPACES
);
17 static void dec_cgroup_namespaces(struct ucounts
*ucounts
)
19 dec_ucount(ucounts
, UCOUNT_CGROUP_NAMESPACES
);
22 static struct cgroup_namespace
*alloc_cgroup_ns(void)
24 struct cgroup_namespace
*new_ns
;
27 new_ns
= kzalloc(sizeof(struct cgroup_namespace
), GFP_KERNEL
);
29 return ERR_PTR(-ENOMEM
);
30 ret
= ns_alloc_inum(&new_ns
->ns
);
35 refcount_set(&new_ns
->ns
.count
, 1);
36 new_ns
->ns
.ops
= &cgroupns_operations
;
40 void free_cgroup_ns(struct cgroup_namespace
*ns
)
42 put_css_set(ns
->root_cset
);
43 dec_cgroup_namespaces(ns
->ucounts
);
44 put_user_ns(ns
->user_ns
);
45 ns_free_inum(&ns
->ns
);
48 EXPORT_SYMBOL(free_cgroup_ns
);
50 struct cgroup_namespace
*copy_cgroup_ns(unsigned long flags
,
51 struct user_namespace
*user_ns
,
52 struct cgroup_namespace
*old_ns
)
54 struct cgroup_namespace
*new_ns
;
55 struct ucounts
*ucounts
;
60 if (!(flags
& CLONE_NEWCGROUP
)) {
61 get_cgroup_ns(old_ns
);
65 /* Allow only sysadmin to create cgroup namespace. */
66 if (!ns_capable(user_ns
, CAP_SYS_ADMIN
))
67 return ERR_PTR(-EPERM
);
69 ucounts
= inc_cgroup_namespaces(user_ns
);
71 return ERR_PTR(-ENOSPC
);
73 /* It is not safe to take cgroup_mutex here */
74 spin_lock_irq(&css_set_lock
);
75 cset
= task_css_set(current
);
77 spin_unlock_irq(&css_set_lock
);
79 new_ns
= alloc_cgroup_ns();
82 dec_cgroup_namespaces(ucounts
);
86 new_ns
->user_ns
= get_user_ns(user_ns
);
87 new_ns
->ucounts
= ucounts
;
88 new_ns
->root_cset
= cset
;
93 static inline struct cgroup_namespace
*to_cg_ns(struct ns_common
*ns
)
95 return container_of(ns
, struct cgroup_namespace
, ns
);
98 static int cgroupns_install(struct nsset
*nsset
, struct ns_common
*ns
)
100 struct nsproxy
*nsproxy
= nsset
->nsproxy
;
101 struct cgroup_namespace
*cgroup_ns
= to_cg_ns(ns
);
103 if (!ns_capable(nsset
->cred
->user_ns
, CAP_SYS_ADMIN
) ||
104 !ns_capable(cgroup_ns
->user_ns
, CAP_SYS_ADMIN
))
107 /* Don't need to do anything if we are attaching to our own cgroupns. */
108 if (cgroup_ns
== nsproxy
->cgroup_ns
)
111 get_cgroup_ns(cgroup_ns
);
112 put_cgroup_ns(nsproxy
->cgroup_ns
);
113 nsproxy
->cgroup_ns
= cgroup_ns
;
118 static struct ns_common
*cgroupns_get(struct task_struct
*task
)
120 struct cgroup_namespace
*ns
= NULL
;
121 struct nsproxy
*nsproxy
;
124 nsproxy
= task
->nsproxy
;
126 ns
= nsproxy
->cgroup_ns
;
131 return ns
? &ns
->ns
: NULL
;
134 static void cgroupns_put(struct ns_common
*ns
)
136 put_cgroup_ns(to_cg_ns(ns
));
139 static struct user_namespace
*cgroupns_owner(struct ns_common
*ns
)
141 return to_cg_ns(ns
)->user_ns
;
144 const struct proc_ns_operations cgroupns_operations
= {
146 .type
= CLONE_NEWCGROUP
,
149 .install
= cgroupns_install
,
150 .owner
= cgroupns_owner
,
153 static __init
int cgroup_namespaces_init(void)
157 subsys_initcall(cgroup_namespaces_init
);