summaryrefslogtreecommitdiff
blob: 8493491d0d6554dcd6f5dbc398797af73a0b89e9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
From b635e92d21d2a4d71a553388f18cfa08f44bf1ba Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner@ubuntu.com>
Date: Mon, 30 Oct 2017 14:16:46 +0100
Subject: [PATCH] cgroups: enable container without CAP_SYS_ADMIN

In case cgroup namespaces are supported but we do not have CAP_SYS_ADMIN we
need to mount cgroups for the container. This patch enables both privileged and
unprivileged containers without CAP_SYS_ADMIN.

Closes #1737.

Signed-off-by: Christian Brauner <christian.brauner@ubuntu.com>
---
 src/lxc/cgroups/cgfs.c   |  3 ++-
 src/lxc/cgroups/cgfsng.c | 52 +++++++++++++++++++++++++++++++++++++++++++++---
 src/lxc/cgroups/cgroup.c |  2 +-
 src/lxc/conf.c           |  3 ---
 src/lxc/conf.h           |  1 +
 5 files changed, 53 insertions(+), 8 deletions(-)

diff --git a/src/lxc/cgroups/cgfs.c b/src/lxc/cgroups/cgfs.c
index bcbd6613..efd627f0 100644
--- a/src/lxc/cgroups/cgfs.c
+++ b/src/lxc/cgroups/cgfs.c
@@ -1418,11 +1418,12 @@ static bool cgroupfs_mount_cgroup(void *hdata, const char *root, int type)
 	struct cgfs_data *cgfs_d;
 	struct cgroup_process_info *info, *base_info;
 	int r, saved_errno = 0;
+	struct lxc_handler *handler = hdata;
 
 	if (cgns_supported())
 		return true;
 
-	cgfs_d = hdata;
+	cgfs_d = handler->cgroup_data;
 	if (!cgfs_d)
 		return false;
 	base_info = cgfs_d->info;
diff --git a/src/lxc/cgroups/cgfsng.c b/src/lxc/cgroups/cgfsng.c
index e43edd7d..ec6440c1 100644
--- a/src/lxc/cgroups/cgfsng.c
+++ b/src/lxc/cgroups/cgfsng.c
@@ -50,6 +50,7 @@
 #include <linux/types.h>
 #include <linux/kdev_t.h>
 
+#include "caps.h"
 #include "cgroup.h"
 #include "cgroup_utils.h"
 #include "commands.h"
@@ -1616,17 +1617,49 @@ do_secondstage_mounts_if_needed(int type, struct hierarchy *h,
 	return 0;
 }
 
+static int mount_cgroup_cgns_supported(struct hierarchy *h, const char *controllerpath)
+{
+	 int ret;
+	 char *controllers = NULL;
+	 char *type = "cgroup2";
+
+	if (!h->is_cgroup_v2) {
+		controllers = lxc_string_join(",", (const char **)h->controllers, false);
+		if (!controllers)
+			return -ENOMEM;
+		type = "cgroup";
+	}
+
+	ret = mount("cgroup", controllerpath, type, MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_RELATIME, controllers);
+	free(controllers);
+	if (ret < 0) {
+		SYSERROR("Failed to mount %s with cgroup filesystem type %s", controllerpath, type);
+		return -1;
+	}
+
+	DEBUG("Mounted %s with cgroup filesystem type %s", controllerpath, type);
+	return 0;
+}
+
 static bool cgfsng_mount(void *hdata, const char *root, int type)
 {
-	struct cgfsng_handler_data *d = hdata;
+	int i;
 	char *tmpfspath = NULL;
 	bool retval = false;
-	int i;
+	struct lxc_handler *handler = hdata;
+	struct cgfsng_handler_data *d = handler->cgroup_data;
+	bool has_cgns = false, has_sys_admin = true;
 
 	if ((type & LXC_AUTO_CGROUP_MASK) == 0)
 		return true;
 
-	if (cgns_supported())
+	has_cgns = cgns_supported();
+	if (!lxc_list_empty(&handler->conf->keepcaps))
+		has_sys_admin = in_caplist(CAP_SYS_ADMIN, &handler->conf->keepcaps);
+	else
+		has_sys_admin = !in_caplist(CAP_SYS_ADMIN, &handler->conf->caps);
+
+	if (has_cgns && has_sys_admin)
 		return true;
 
 	tmpfspath = must_make_path(root, "/sys/fs/cgroup", NULL);
@@ -1662,6 +1695,19 @@ static bool cgfsng_mount(void *hdata, const char *root, int type)
 			free(controllerpath);
 			goto bad;
 		}
+
+		if (has_cgns && !has_sys_admin) {
+			/* If cgroup namespaces are supported but the container
+			 * will not have CAP_SYS_ADMIN after it has started we
+			 * need to mount the cgroups manually.
+			 */
+			r = mount_cgroup_cgns_supported(h, controllerpath);
+			free(controllerpath);
+			if (r < 0)
+				goto bad;
+			continue;
+		}
+
 		if (mount_cgroup_full(type, h, controllerpath, d->container_cgroup) < 0) {
 			free(controllerpath);
 			goto bad;
diff --git a/src/lxc/cgroups/cgroup.c b/src/lxc/cgroups/cgroup.c
index 674e3090..36a665b1 100644
--- a/src/lxc/cgroups/cgroup.c
+++ b/src/lxc/cgroups/cgroup.c
@@ -166,7 +166,7 @@ bool cgroup_chown(struct lxc_handler *handler)
 bool cgroup_mount(const char *root, struct lxc_handler *handler, int type)
 {
 	if (ops)
-		return ops->mount_cgroup(handler->cgroup_data, root, type);
+		return ops->mount_cgroup(handler, root, type);
 
 	return false;
 }
diff --git a/src/lxc/conf.c b/src/lxc/conf.c
index d2fab945..44d97843 100644
--- a/src/lxc/conf.c
+++ b/src/lxc/conf.c
@@ -210,9 +210,6 @@ __thread struct lxc_conf *current_config;
 struct lxc_conf *current_config;
 #endif
 
-/* Declare this here, since we don't want to reshuffle the whole file. */
-static int in_caplist(int cap, struct lxc_list *caps);
-
 static struct mount_opt mount_opt[] = {
 	{ "async",         1, MS_SYNCHRONOUS },
 	{ "atime",         1, MS_NOATIME     },
diff --git a/src/lxc/conf.h b/src/lxc/conf.h
index c61f861e..63e71e2d 100644
--- a/src/lxc/conf.h
+++ b/src/lxc/conf.h
@@ -402,5 +402,6 @@ extern unsigned long add_required_remount_flags(const char *s, const char *d,
 						unsigned long flags);
 extern int run_script(const char *name, const char *section, const char *script,
 		      ...);
+extern int in_caplist(int cap, struct lxc_list *caps);
 
 #endif /* __LXC_CONF_H */
-- 
2.13.6