]> git.proxmox.com Git - lxc.git/blob - debian/patches/0001-separate-the-limiting-from-the-namespaced-cgroup-roo.patch
update to lxc-2.0.6
[lxc.git] / debian / patches / 0001-separate-the-limiting-from-the-namespaced-cgroup-roo.patch
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
5
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.*.
10
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.
14
15 Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
16 ---
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 +++----
22 src/lxc/criu.c | 2 +-
23 src/lxc/start.c | 21 +++++++++++--
24 7 files changed, 116 insertions(+), 37 deletions(-)
25
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)
31 free(d);
32 }
33
34 -static inline bool cgfs_create(void *hdata)
35 +static inline bool cgfs_create(void *hdata, bool inner)
36 {
37 struct cgfs_data *d = hdata;
38 struct cgroup_process_info *i;
39 struct cgroup_meta_data *md;
40
41 + if (inner)
42 + return true;
43 +
44 if (!d)
45 return false;
46 md = d->meta;
47 @@ -2399,12 +2402,15 @@ static inline bool cgfs_create(void *hdata)
48 return true;
49 }
50
51 -static inline bool cgfs_enter(void *hdata, pid_t pid)
52 +static inline bool cgfs_enter(void *hdata, pid_t pid, bool inner)
53 {
54 struct cgfs_data *d = hdata;
55 struct cgroup_process_info *i;
56 int ret;
57
58 + if (inner)
59 + return true;
60 +
61 if (!d)
62 return false;
63 i = d->info;
64 @@ -2646,13 +2652,16 @@ static bool do_cgfs_chown(char *cgroup_path, struct lxc_conf *conf)
65 return true;
66 }
67
68 -static bool cgfs_chown(void *hdata, struct lxc_conf *conf)
69 +static bool cgfs_chown(void *hdata, struct lxc_conf *conf, bool inner)
70 {
71 struct cgfs_data *d = hdata;
72 struct cgroup_process_info *info_ptr;
73 char *cgpath;
74 bool r = true;
75
76 + if (inner)
77 + return true;
78 +
79 if (!d)
80 return false;
81
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)
87 return &cgfsng_ops;
88 }
89
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)
92 {
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);
96 - return false;
97 - }
98 - if (!handle_cpuset_hierarchy(h, cgname)) {
99 - ERROR("Failed to handle cgroupfs v1 cpuset controller.");
100 - return false;
101 + char *path;
102 + if (inner) {
103 + path = must_make_path(h->fullcgpath, "ns", NULL);
104 + } else {
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);
109 + return false;
110 + }
111 + if (!handle_cpuset_hierarchy(h, cgname)) {
112 + ERROR("Failed to handle cgroupfs v1 cpuset controller.");
113 + return false;
114 + }
115 }
116 - return mkdir_p(h->fullcgpath, 0755) == 0;
117 + return mkdir_p(path, 0755) == 0;
118 }
119
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
124 */
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)
128 {
129 struct cgfsng_handler_data *d = hdata;
130 char *tmp, *cgname, *offset;
131 @@ -1339,9 +1346,15 @@ static inline bool cgfsng_create(void *hdata)
132 if (!d)
133 return false;
134 if (d->container_cgroup) {
135 + if (inner)
136 + return cgfsng_create_inner(d);
137 WARN("cgfsng_create called a second time");
138 return false;
139 }
140 + if (inner) {
141 + ERROR("cgfsng_create called twice for innner cgroup");
142 + return false;
143 + }
144
145 tmp = lxc_string_replace("%n", d->name, d->cgroup_pattern);
146 if (!tmp) {
147 @@ -1362,7 +1375,7 @@ again:
148 if (idx)
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)) {
153 int j;
154 SYSERROR("Failed to create %s: %s", hierarchies[i]->fullcgpath, strerror(errno));
155 free(hierarchies[i]->fullcgpath);
156 @@ -1382,7 +1395,24 @@ out_free:
157 return false;
158 }
159
160 -static bool cgfsng_enter(void *hdata, pid_t pid)
161 +static inline bool cgfsng_create_inner(struct cgfsng_handler_data *d)
162 +{
163 + size_t i;
164 + bool ret = true;
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));
169 + ret = false;
170 + break;
171 + }
172 + }
173 + free(cgname);
174 + return ret;
175 +}
176 +
177 +
178 +static bool cgfsng_enter(void *hdata, pid_t pid, bool inner)
179 {
180 char pidstr[25];
181 int i, len;
182 @@ -1392,7 +1422,12 @@ static bool cgfsng_enter(void *hdata, pid_t pid)
183 return false;
184
185 for (i = 0; hierarchies[i]; i++) {
186 - char *fullpath = must_make_path(hierarchies[i]->fullcgpath,
187 + char *fullpath;
188 + if (inner)
189 + fullpath = must_make_path(hierarchies[i]->fullcgpath, "ns",
190 + "cgroup.procs", NULL);
191 + else
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)
197 struct chown_data {
198 struct cgfsng_handler_data *d;
199 uid_t origuid; // target uid in parent namespace
200 + bool inner;
201 };
202
203 /*
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;
207
208 + if (arg->inner)
209 + path = must_make_path(path, "ns", NULL);
210 +
211 if (chown(path, destuid, 0) < 0) {
212 SYSERROR("Error chowning %s to %d", path, (int) destuid);
213 + if (arg->inner)
214 + free(path);
215 return -1;
216 }
217
218 if (chmod(path, 0775) < 0) {
219 SYSERROR("Error chmoding %s", path);
220 + if (arg->inner)
221 + free(path);
222 return -1;
223 }
224
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);
228 free(fullpath);
229 +
230 + free(path);
231 }
232
233 return 0;
234 }
235
236 -static bool cgfsns_chown(void *hdata, struct lxc_conf *conf)
237 +static bool cgfsns_chown(void *hdata, struct lxc_conf *conf, bool inner)
238 {
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)
242
243 wrap.d = d;
244 wrap.origuid = geteuid();
245 + wrap.inner = inner;
246
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);
255 }
256
257 -static inline bool cgm_create(void *hdata)
258 +static inline bool cgm_create(void *hdata, bool inner)
259 {
260 struct cgm_data *d = hdata;
261 char **slist = subsystems;
262 @@ -617,6 +617,9 @@ static inline bool cgm_create(void *hdata)
263 int32_t existed;
264 char result[MAXPATHLEN], *tmp, *cgroup_path;
265
266 + if (inner)
267 + return true;
268 +
269 if (!d)
270 return false;
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,
273 return true;
274 }
275
276 -static inline bool cgm_enter(void *hdata, pid_t pid)
277 +static inline bool cgm_enter(void *hdata, pid_t pid, bool inner)
278 {
279 struct cgm_data *d = hdata;
280 char **slist = subsystems;
281 bool ret = false;
282 int i;
283
284 + if (inner)
285 + return true;
286 +
287 if (!d || !d->cgroup_path)
288 return false;
289
290 @@ -1541,10 +1547,13 @@ out:
291 return ret;
292 }
293
294 -static bool cgm_chown(void *hdata, struct lxc_conf *conf)
295 +static bool cgm_chown(void *hdata, struct lxc_conf *conf, bool inner)
296 {
297 struct cgm_data *d = hdata;
298
299 + if (inner)
300 + return true;
301 +
302 if (!d || !d->cgroup_path)
303 return false;
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)
310 }
311
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)
315 {
316 if (ops)
317 - return ops->create(handler->cgroup_data);
318 + return ops->create(handler->cgroup_data, inner);
319 return false;
320 }
321
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
325 */
326 -bool cgroup_enter(struct lxc_handler *handler)
327 +bool cgroup_enter(struct lxc_handler *handler, bool inner)
328 {
329 if (ops)
330 - return ops->enter(handler->cgroup_data, handler->pid);
331 + return ops->enter(handler->cgroup_data, handler->pid, inner);
332 return false;
333 }
334
335 @@ -150,10 +150,10 @@ bool cgroup_setup_limits(struct lxc_handler *handler, bool with_devices)
336 return false;
337 }
338
339 -bool cgroup_chown(struct lxc_handler *handler)
340 +bool cgroup_chown(struct lxc_handler *handler, bool inner)
341 {
342 if (ops && ops->chown)
343 - return ops->chown(handler->cgroup_data, handler->conf);
344 + return ops->chown(handler->cgroup_data, handler->conf, inner);
345 return true;
346 }
347
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 {
353
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);
362 bool (*escape)();
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
388 --- a/src/lxc/criu.c
389 +++ b/src/lxc/criu.c
390 @@ -797,7 +797,7 @@ static void do_restore(struct lxc_container *c, int status_pipe, struct migrate_
391 goto out_fini_handler;
392 }
393
394 - if (!cgroup_create(handler)) {
395 + if (!cgroup_create(handler, false)) {
396 ERROR("failed creating groups");
397 goto out_fini_handler;
398 }
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)
404
405 cgroups_connected = true;
406
407 - if (!cgroup_create(handler)) {
408 + if (!cgroup_create(handler, false)) {
409 ERROR("Failed creating cgroups.");
410 goto out_delete_net;
411 }
412 @@ -1208,10 +1208,10 @@ static int lxc_spawn(struct lxc_handler *handler)
413 goto out_delete_net;
414 }
415
416 - if (!cgroup_enter(handler))
417 + if (!cgroup_enter(handler, false))
418 goto out_delete_net;
419
420 - if (!cgroup_chown(handler))
421 + if (!cgroup_chown(handler, false))
422 goto out_delete_net;
423
424 if (failed_before_rename)
425 @@ -1254,6 +1254,21 @@ static int lxc_spawn(struct lxc_handler *handler)
426 goto out_delete_net;
427 }
428
429 + if (cgns_supported()) {
430 + if (!cgroup_create(handler, true)) {
431 + ERROR("failed to create inner cgroup separation layer");
432 + goto out_delete_net;
433 + }
434 + if (!cgroup_enter(handler, true)) {
435 + ERROR("failed to enter inner cgroup separation layer");
436 + goto out_delete_net;
437 + }
438 + if (!cgroup_chown(handler, true)) {
439 + ERROR("failed chown inner cgroup separation layer");
440 + goto out_delete_net;
441 + }
442 + }
443 +
444 cgroup_disconnect();
445 cgroups_connected = false;
446
447 --
448 2.1.4
449