1 From a3743ab2816d54fbe9854a5a9f31cc62b01b5339 Mon Sep 17 00:00:00 2001
2 From: Wolfgang Bumiller <w.bumiller@proxmox.com>
3 Date: Tue, 15 Nov 2016 09:20:24 +0100
4 Subject: [PATCH 1/2] separate the limiting from the namespaced cgroup root
6 When cgroup namespaces are enabled a privileged container
7 with mixed cgroups has full write access to its own root
8 cgroup effectively allowing it to overwrite values written
9 from the outside or configured via lxc.cgroup.*.
11 This patch causes an additional 'ns/' directory to be
12 created in all cgroups if cgroup namespaces and cgfsng are
13 being used in order to combat this.
15 Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
17 src/lxc/cgroups/cgfs.c | 15 +++++++--
18 src/lxc/cgroups/cgfsng.c | 76 ++++++++++++++++++++++++++++++++++++---------
19 src/lxc/cgroups/cgmanager.c | 15 +++++++--
20 src/lxc/cgroups/cgroup.c | 12 +++----
21 src/lxc/cgroups/cgroup.h | 12 +++----
23 src/lxc/start.c | 21 +++++++++++--
24 7 files changed, 116 insertions(+), 37 deletions(-)
26 diff --git a/src/lxc/cgroups/cgfs.c b/src/lxc/cgroups/cgfs.c
27 index 8499200..0152477 100644
28 --- a/src/lxc/cgroups/cgfs.c
29 +++ b/src/lxc/cgroups/cgfs.c
30 @@ -2383,12 +2383,15 @@ static void cgfs_destroy(void *hdata, struct lxc_conf *conf)
34 -static inline bool cgfs_create(void *hdata)
35 +static inline bool cgfs_create(void *hdata, bool inner)
37 struct cgfs_data *d = hdata;
38 struct cgroup_process_info *i;
39 struct cgroup_meta_data *md;
47 @@ -2399,12 +2402,15 @@ static inline bool cgfs_create(void *hdata)
51 -static inline bool cgfs_enter(void *hdata, pid_t pid)
52 +static inline bool cgfs_enter(void *hdata, pid_t pid, bool inner)
54 struct cgfs_data *d = hdata;
55 struct cgroup_process_info *i;
64 @@ -2646,13 +2652,16 @@ static bool do_cgfs_chown(char *cgroup_path, struct lxc_conf *conf)
68 -static bool cgfs_chown(void *hdata, struct lxc_conf *conf)
69 +static bool cgfs_chown(void *hdata, struct lxc_conf *conf, bool inner)
71 struct cgfs_data *d = hdata;
72 struct cgroup_process_info *info_ptr;
82 diff --git a/src/lxc/cgroups/cgfsng.c b/src/lxc/cgroups/cgfsng.c
83 index d3215d7..123c67c 100644
84 --- a/src/lxc/cgroups/cgfsng.c
85 +++ b/src/lxc/cgroups/cgfsng.c
86 @@ -1303,18 +1303,24 @@ struct cgroup_ops *cgfsng_ops_init(void)
90 -static bool create_path_for_hierarchy(struct hierarchy *h, char *cgname)
91 +static bool create_path_for_hierarchy(struct hierarchy *h, char *cgname, bool inner)
93 - h->fullcgpath = must_make_path(h->mountpoint, h->base_cgroup, cgname, NULL);
94 - if (dir_exists(h->fullcgpath)) { // it must not already exist
95 - ERROR("Path \"%s\" already existed.", h->fullcgpath);
98 - if (!handle_cpuset_hierarchy(h, cgname)) {
99 - ERROR("Failed to handle cgroupfs v1 cpuset controller.");
103 + path = must_make_path(h->fullcgpath, "ns", NULL);
105 + path = must_make_path(h->mountpoint, h->base_cgroup, cgname, NULL);
106 + h->fullcgpath = path;
107 + if (dir_exists(h->fullcgpath)) { // it must not already exist
108 + ERROR("Path \"%s\" already existed.", h->fullcgpath);
111 + if (!handle_cpuset_hierarchy(h, cgname)) {
112 + ERROR("Failed to handle cgroupfs v1 cpuset controller.");
116 - return mkdir_p(h->fullcgpath, 0755) == 0;
117 + return mkdir_p(path, 0755) == 0;
120 static void remove_path_for_hierarchy(struct hierarchy *h, char *cgname)
121 @@ -1329,7 +1335,8 @@ static void remove_path_for_hierarchy(struct hierarchy *h, char *cgname)
122 * Try to create the same cgroup in all hierarchies.
123 * Start with cgroup_pattern; next cgroup_pattern-1, -2, ..., -999
125 -static inline bool cgfsng_create(void *hdata)
126 +static inline bool cgfsng_create_inner(struct cgfsng_handler_data*);
127 +static inline bool cgfsng_create(void *hdata, bool inner)
129 struct cgfsng_handler_data *d = hdata;
130 char *tmp, *cgname, *offset;
131 @@ -1339,9 +1346,15 @@ static inline bool cgfsng_create(void *hdata)
134 if (d->container_cgroup) {
136 + return cgfsng_create_inner(d);
137 WARN("cgfsng_create called a second time");
141 + ERROR("cgfsng_create called twice for innner cgroup");
145 tmp = lxc_string_replace("%n", d->name, d->cgroup_pattern);
147 @@ -1362,7 +1375,7 @@ again:
149 snprintf(offset, 5, "-%d", idx);
150 for (i = 0; hierarchies[i]; i++) {
151 - if (!create_path_for_hierarchy(hierarchies[i], cgname)) {
152 + if (!create_path_for_hierarchy(hierarchies[i], cgname, false)) {
154 SYSERROR("Failed to create %s: %s", hierarchies[i]->fullcgpath, strerror(errno));
155 free(hierarchies[i]->fullcgpath);
156 @@ -1382,7 +1395,24 @@ out_free:
160 -static bool cgfsng_enter(void *hdata, pid_t pid)
161 +static inline bool cgfsng_create_inner(struct cgfsng_handler_data *d)
165 + char *cgname = must_make_path(d->container_cgroup, "ns", NULL);
166 + for (i = 0; hierarchies[i]; i++) {
167 + if (!create_path_for_hierarchy(hierarchies[i], cgname, true)) {
168 + SYSERROR("Failed to create %s/ns: %s", hierarchies[i]->fullcgpath, strerror(errno));
178 +static bool cgfsng_enter(void *hdata, pid_t pid, bool inner)
182 @@ -1392,7 +1422,12 @@ static bool cgfsng_enter(void *hdata, pid_t pid)
185 for (i = 0; hierarchies[i]; i++) {
186 - char *fullpath = must_make_path(hierarchies[i]->fullcgpath,
189 + fullpath = must_make_path(hierarchies[i]->fullcgpath, "ns",
190 + "cgroup.procs", NULL);
192 + fullpath = must_make_path(hierarchies[i]->fullcgpath,
193 "cgroup.procs", NULL);
194 if (lxc_write_to_file(fullpath, pidstr, len, false) != 0) {
195 SYSERROR("Failed to enter %s", fullpath);
196 @@ -1408,6 +1443,7 @@ static bool cgfsng_enter(void *hdata, pid_t pid)
198 struct cgfsng_handler_data *d;
199 uid_t origuid; // target uid in parent namespace
204 @@ -1436,13 +1472,20 @@ static int chown_cgroup_wrapper(void *data)
205 for (i = 0; hierarchies[i]; i++) {
206 char *fullpath, *path = hierarchies[i]->fullcgpath;
209 + path = must_make_path(path, "ns", NULL);
211 if (chown(path, destuid, 0) < 0) {
212 SYSERROR("Error chowning %s to %d", path, (int) destuid);
218 if (chmod(path, 0775) < 0) {
219 SYSERROR("Error chmoding %s", path);
225 @@ -1466,12 +1509,14 @@ static int chown_cgroup_wrapper(void *data)
226 if (chmod(fullpath, 0664) < 0)
227 WARN("Error chmoding %s: %m", path);
236 -static bool cgfsns_chown(void *hdata, struct lxc_conf *conf)
237 +static bool cgfsns_chown(void *hdata, struct lxc_conf *conf, bool inner)
239 struct cgfsng_handler_data *d = hdata;
240 struct chown_data wrap;
241 @@ -1484,6 +1529,7 @@ static bool cgfsns_chown(void *hdata, struct lxc_conf *conf)
244 wrap.origuid = geteuid();
245 + wrap.inner = inner;
247 if (userns_exec_1(conf, chown_cgroup_wrapper, &wrap) < 0) {
248 ERROR("Error requesting cgroup chown in new namespace");
249 diff --git a/src/lxc/cgroups/cgmanager.c b/src/lxc/cgroups/cgmanager.c
250 index f2756b0..86a9a1f 100644
251 --- a/src/lxc/cgroups/cgmanager.c
252 +++ b/src/lxc/cgroups/cgmanager.c
253 @@ -609,7 +609,7 @@ static inline void cleanup_cgroups(char *path)
254 cgm_remove_cgroup(slist[i], path);
257 -static inline bool cgm_create(void *hdata)
258 +static inline bool cgm_create(void *hdata, bool inner)
260 struct cgm_data *d = hdata;
261 char **slist = subsystems;
262 @@ -617,6 +617,9 @@ static inline bool cgm_create(void *hdata)
264 char result[MAXPATHLEN], *tmp, *cgroup_path;
271 // XXX we should send a hint to the cgmanager that when these
272 @@ -709,13 +712,16 @@ static bool lxc_cgmanager_enter(pid_t pid, const char *controller,
276 -static inline bool cgm_enter(void *hdata, pid_t pid)
277 +static inline bool cgm_enter(void *hdata, pid_t pid, bool inner)
279 struct cgm_data *d = hdata;
280 char **slist = subsystems;
287 if (!d || !d->cgroup_path)
290 @@ -1541,10 +1547,13 @@ out:
294 -static bool cgm_chown(void *hdata, struct lxc_conf *conf)
295 +static bool cgm_chown(void *hdata, struct lxc_conf *conf, bool inner)
297 struct cgm_data *d = hdata;
302 if (!d || !d->cgroup_path)
304 if (!cgm_dbus_connect()) {
305 diff --git a/src/lxc/cgroups/cgroup.c b/src/lxc/cgroups/cgroup.c
306 index 78472d4..9f4e15f 100644
307 --- a/src/lxc/cgroups/cgroup.c
308 +++ b/src/lxc/cgroups/cgroup.c
309 @@ -80,10 +80,10 @@ void cgroup_destroy(struct lxc_handler *handler)
312 /* Create the container cgroups for all requested controllers */
313 -bool cgroup_create(struct lxc_handler *handler)
314 +bool cgroup_create(struct lxc_handler *handler, bool inner)
317 - return ops->create(handler->cgroup_data);
318 + return ops->create(handler->cgroup_data, inner);
322 @@ -91,10 +91,10 @@ bool cgroup_create(struct lxc_handler *handler)
323 * Enter the container init into its new cgroups for all
324 * requested controllers
326 -bool cgroup_enter(struct lxc_handler *handler)
327 +bool cgroup_enter(struct lxc_handler *handler, bool inner)
330 - return ops->enter(handler->cgroup_data, handler->pid);
331 + return ops->enter(handler->cgroup_data, handler->pid, inner);
335 @@ -150,10 +150,10 @@ bool cgroup_setup_limits(struct lxc_handler *handler, bool with_devices)
339 -bool cgroup_chown(struct lxc_handler *handler)
340 +bool cgroup_chown(struct lxc_handler *handler, bool inner)
342 if (ops && ops->chown)
343 - return ops->chown(handler->cgroup_data, handler->conf);
344 + return ops->chown(handler->cgroup_data, handler->conf, inner);
348 diff --git a/src/lxc/cgroups/cgroup.h b/src/lxc/cgroups/cgroup.h
349 index 11b251e..4a2b070 100644
350 --- a/src/lxc/cgroups/cgroup.h
351 +++ b/src/lxc/cgroups/cgroup.h
352 @@ -43,8 +43,8 @@ struct cgroup_ops {
354 void *(*init)(const char *name);
355 void (*destroy)(void *hdata, struct lxc_conf *conf);
356 - bool (*create)(void *hdata);
357 - bool (*enter)(void *hdata, pid_t pid);
358 + bool (*create)(void *hdata, bool inner);
359 + bool (*enter)(void *hdata, pid_t pid, bool inner);
360 bool (*create_legacy)(void *hdata, pid_t pid);
361 const char *(*get_cgroup)(void *hdata, const char *subsystem);
363 @@ -54,7 +54,7 @@ struct cgroup_ops {
364 int (*get)(const char *filename, char *value, size_t len, const char *name, const char *lxcpath);
365 bool (*unfreeze)(void *hdata);
366 bool (*setup_limits)(void *hdata, struct lxc_list *cgroup_conf, bool with_devices);
367 - bool (*chown)(void *hdata, struct lxc_conf *conf);
368 + bool (*chown)(void *hdata, struct lxc_conf *conf, bool inner);
369 bool (*attach)(const char *name, const char *lxcpath, pid_t pid);
370 bool (*mount_cgroup)(void *hdata, const char *root, int type);
371 int (*nrtasks)(void *hdata);
372 @@ -66,10 +66,10 @@ extern bool cgroup_attach(const char *name, const char *lxcpath, pid_t pid);
373 extern bool cgroup_mount(const char *root, struct lxc_handler *handler, int type);
374 extern void cgroup_destroy(struct lxc_handler *handler);
375 extern bool cgroup_init(struct lxc_handler *handler);
376 -extern bool cgroup_create(struct lxc_handler *handler);
377 +extern bool cgroup_create(struct lxc_handler *handler, bool inner);
378 extern bool cgroup_setup_limits(struct lxc_handler *handler, bool with_devices);
379 -extern bool cgroup_chown(struct lxc_handler *handler);
380 -extern bool cgroup_enter(struct lxc_handler *handler);
381 +extern bool cgroup_chown(struct lxc_handler *handler, bool inner);
382 +extern bool cgroup_enter(struct lxc_handler *handler, bool inner);
383 extern void cgroup_cleanup(struct lxc_handler *handler);
384 extern bool cgroup_create_legacy(struct lxc_handler *handler);
385 extern int cgroup_nrtasks(struct lxc_handler *handler);
386 diff --git a/src/lxc/criu.c b/src/lxc/criu.c
387 index 50a7400..8933d9a 100644
390 @@ -797,7 +797,7 @@ static void do_restore(struct lxc_container *c, int status_pipe, struct migrate_
391 goto out_fini_handler;
394 - if (!cgroup_create(handler)) {
395 + if (!cgroup_create(handler, false)) {
396 ERROR("failed creating groups");
397 goto out_fini_handler;
399 diff --git a/src/lxc/start.c b/src/lxc/start.c
400 index 71206e0..c9d78b7 100644
401 --- a/src/lxc/start.c
402 +++ b/src/lxc/start.c
403 @@ -1121,7 +1121,7 @@ static int lxc_spawn(struct lxc_handler *handler)
405 cgroups_connected = true;
407 - if (!cgroup_create(handler)) {
408 + if (!cgroup_create(handler, false)) {
409 ERROR("Failed creating cgroups.");
412 @@ -1208,10 +1208,10 @@ static int lxc_spawn(struct lxc_handler *handler)
416 - if (!cgroup_enter(handler))
417 + if (!cgroup_enter(handler, false))
420 - if (!cgroup_chown(handler))
421 + if (!cgroup_chown(handler, false))
424 if (failed_before_rename)
425 @@ -1254,6 +1254,21 @@ static int lxc_spawn(struct lxc_handler *handler)
429 + if (cgns_supported()) {
430 + if (!cgroup_create(handler, true)) {
431 + ERROR("failed to create inner cgroup separation layer");
432 + goto out_delete_net;
434 + if (!cgroup_enter(handler, true)) {
435 + ERROR("failed to enter inner cgroup separation layer");
436 + goto out_delete_net;
438 + if (!cgroup_chown(handler, true)) {
439 + ERROR("failed chown inner cgroup separation layer");
440 + goto out_delete_net;
445 cgroups_connected = false;