[lxc-devel] [PATCH 9/5] cgroup: special-case the cgroups used for unprivileged containers

Serge Hallyn serge.hallyn at ubuntu.com
Thu Jul 25 21:59:07 UTC 2013


When creating an unprivileged container, you must have a cgroup
fs mounted named lxc.  For instance

	mkdir /sys/fs/cgroup/lxc
	mount -t cgroup -o none,name=lxc none /sys/fs/cgroup/lxc
	mkdir /sys/fs/cgroup/lxc/$USER
	chown -R $USER /sys/fs/cgroup/lxc/$USER

You could also compose the freezer subsystem with the lxc one to
not lose freezer support.  When I tested that I was able to do
unprivileged lxc-freeze and lxc-unfreeze of my own containers.

Unprivileged containers will ONLY enter a per-container cgroup for
the lxc cgroup.  If you wish to set other limits, you need privilege
to do so anyway, so you can do so out of band with a separate
(privileged) set of utilities.  For instance you can confine the
whole user to a cpuset with pam_cgroup, or allow the user to
create and enter cgroups of certain subsystems if it makes sense.

(For reference, this is done in response to upstream cgroup kernel
maintainer specifically recmomending against delegating cgroup
administration to users.  It is safe for some but not all cgroups,
and it does not fit in with the future plans)

Signed-off-by: Serge Hallyn <serge.hallyn at ubuntu.com>
---
 src/lxc/cgroup.c | 58 ++++++++++++++++++++++++++++++++++++--------------------
 1 file changed, 37 insertions(+), 21 deletions(-)

diff --git a/src/lxc/cgroup.c b/src/lxc/cgroup.c
index 654e55a..ff3a090 100644
--- a/src/lxc/cgroup.c
+++ b/src/lxc/cgroup.c
@@ -579,6 +579,24 @@ static int record_visited(char *opts, char **visitedp, char *allcgroups)
 	return 0;
 }
 
+static inline bool filter_cgroup_mntent(struct mntent *m)
+{
+	if (strcmp(m->mnt_type, "cgroup") != 0)
+		return false;
+	/*
+	 * if we are unprivileged, then only use one named 'lxc'
+	 * otherwise, use all the ones which have subsystems
+	 */
+	if (geteuid() == 0) {
+		if (!mount_has_subsystem(m))
+			return false;
+	} else {
+		if (!hasmntopt(m, "name=lxc"))
+			return false;
+	}
+	return true;
+}
+
 /*
  * Make sure the 'cgroup group' exists, so that we don't have to worry about
  * that later.
@@ -605,10 +623,7 @@ static int create_lxcgroups(const char *lxcgroup)
 	}
 
 	while ((getmntent_r(file, &mntent_r, buf, sizeof(buf)))) {
-
-		if (strcmp(mntent_r.mnt_type, "cgroup"))
-			continue;
-		if (!mount_has_subsystem(&mntent_r))
+		if (!filter_cgroup_mntent(&mntent_r))
 			continue;
 
 		/*
@@ -698,9 +713,7 @@ again:
 
 	while ((getmntent_r(file, &mntent_r, buf, sizeof(buf)))) {
 
-		if (strcmp(mntent_r.mnt_type, "cgroup"))
-			continue;
-		if (!mount_has_subsystem(&mntent_r))
+		if (!filter_cgroup_mntent(&mntent_r))
 			continue;
 
 		/* make sure we haven't checked this subsystem already */
@@ -771,10 +784,9 @@ int lxc_cgroup_enter(const char *cgpath, pid_t pid)
 	}
 
 	while ((getmntent_r(file, &mntent_r, buf, sizeof(buf)))) {
-		if (strcmp(mntent_r.mnt_type, "cgroup"))
-			continue;
-		if (!mount_has_subsystem(&mntent_r))
+		if (!filter_cgroup_mntent(&mntent_r))
 			continue;
+
 		ret = snprintf(path, MAXPATHLEN, "%s/%s/tasks",
 			       mntent_r.mnt_dir, cgpath);
 		if (ret < 0 || ret >= MAXPATHLEN) {
@@ -881,9 +893,7 @@ int lxc_cgroup_destroy(const char *cgpath)
 	}
 
 	while ((getmntent_r(file, &mntent_r, buf, sizeof(buf)))) {
-		if (strcmp(mntent_r.mnt_type, "cgroup"))
-			continue;
-		if (!mount_has_subsystem(&mntent_r))
+		if (!filter_cgroup_mntent(&mntent_r))
 			continue;
 
 		err = lxc_one_cgroup_destroy(&mntent_r, cgpath);
@@ -951,14 +961,13 @@ bool is_in_subcgroup(int pid, const char *subsystem, const char *cgpath)
 
 /*
  * Return cgroup of current task.
- * This assumes that task is in the same cgroup for each controller.  This
- * may or may not *always* be a reasonable assumption - it generally is,
- * and handling or at least checking for this condition is a TODO.
+ * If we are root, then return the 'devices' cgroup.
+ * If we are not, then return the 'name=lxc' cgroup.
  */
 int lxc_curcgroup(char *cgroup, int inlen)
 {
 	FILE *f;
-	char *line = NULL, *p, *p2;
+	char *line = NULL, *p, *p2, *needle;
 	int ret = 0;
 	size_t len;
 
@@ -967,12 +976,19 @@ int lxc_curcgroup(char *cgroup, int inlen)
 		return -1;
 
 	while (getline(&line, &len, f) != -1) {
-		if (strstr(line, ":freezer:") == NULL && strstr(line, ":devices:") == NULL)
-			continue;
-		p = rindex(line, ':');
+		p = index(line, ':');
 		if (!p)
 			continue;
-		p++;
+		p2 = index(p+1, ':');
+		if (!p2)
+			continue;
+		if (geteuid() == 0)
+			needle = strstr(p, "devices");
+		else
+			needle = strstr(p, "name=lxc");
+		if (needle == NULL || needle > p2)
+			continue;
+		p = p2 + 1;
 		len = strlen(p) + 1;
 		p2 = p + len - 2;
 		while (*p2 == '\n') { len--; *p2 = '\0'; p2--; }
-- 
1.8.3.2





More information about the lxc-devel mailing list