[lxc-devel] [lxc/master] cgroups: use of /sys/kernel/cgroup/delegate file

brauner on Github lxc-bot at linuxcontainers.org
Fri Feb 1 10:04:22 UTC 2019


A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 477 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20190201/e2bc5b8f/attachment.bin>
-------------- next part --------------
From 18aae901b695e7fccb8843c41888bac3e0b0f212 Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Fri, 1 Feb 2019 10:57:49 +0100
Subject: [PATCH] cgroups: use of /sys/kernel/cgroup/delegate file

This file contains the files one needs to chown to successfully delegate
cgroup files to unprivileged users.

Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
 src/lxc/cgroups/cgfsng.c | 63 +++++++++++++++++++++++++++++++---------
 src/lxc/cgroups/cgroup.c | 10 +++++--
 src/lxc/cgroups/cgroup.h |  5 ++++
 src/lxc/lxccontainer.h   |  6 ++++
 4 files changed, 67 insertions(+), 17 deletions(-)

diff --git a/src/lxc/cgroups/cgfsng.c b/src/lxc/cgroups/cgfsng.c
index c4fc65252..5f0684bdb 100644
--- a/src/lxc/cgroups/cgfsng.c
+++ b/src/lxc/cgroups/cgfsng.c
@@ -1640,13 +1640,11 @@ static int chown_cgroup_wrapper(void *data)
 		if (arg->hierarchies[i]->version != CGROUP2_SUPER_MAGIC)
 			continue;
 
-		fullpath = must_make_path(path, "cgroup.subtree_control", NULL);
-		(void)chowmod(fullpath, destuid, nsgid, 0664);
-		free(fullpath);
-
-		fullpath = must_make_path(path, "cgroup.threads", NULL);
-		(void)chowmod(fullpath, destuid, nsgid, 0664);
-		free(fullpath);
+		for (char **p = arg->hierarchies[i]->cgroup2_chown; p && *p; p++) {
+			fullpath = must_make_path(path, *p, NULL);
+			(void)chowmod(fullpath, destuid, nsgid, 0664);
+			free(fullpath);
+		}
 	}
 
 	return 0;
@@ -2524,10 +2522,40 @@ static bool cgroup_use_wants_controllers(const struct cgroup_ops *ops,
 	return true;
 }
 
+static void cg_unified_delegate(char ***delegate)
+{
+	char *tmp;
+	int idx;
+	char *standard[] = {"cgroup.subtree_control", "cgroup.threads", NULL};
+
+	tmp = read_file("/sys/kernel/cgroup/delegate");
+	if (!tmp) {
+		for (char **p = standard; p && *p; p++) {
+			idx = append_null_to_list((void ***)delegate);
+			(*delegate)[idx] = must_copy_string(*p);
+		}
+	} else {
+		char *token;
+		lxc_iterate_parts (token, tmp, " \t\n") {
+			/*
+			 * We always need to chown this for both cgroup and
+			 * cgroup2.
+			 */
+			if (strcmp(token, "cgroup.procs") == 0)
+				continue;
+
+			idx = append_null_to_list((void ***)delegate);
+			(*delegate)[idx] = must_copy_string(token);
+		}
+		free(tmp);
+	}
+}
+
 /* At startup, parse_hierarchies finds all the info we need about cgroup
  * mountpoints and current cgroups, and stores it in @d.
  */
-static bool cg_hybrid_init(struct cgroup_ops *ops, bool relative)
+static bool cg_hybrid_init(struct cgroup_ops *ops, bool relative,
+			   bool unprivileged)
 {
 	int ret;
 	char *basecginfo;
@@ -2642,8 +2670,11 @@ static bool cg_hybrid_init(struct cgroup_ops *ops, bool relative)
 			goto next;
 
 		new = add_hierarchy(&ops->hierarchies, controller_list, mountpoint, base_cgroup, type);
-		if (type == CGROUP2_SUPER_MAGIC && !ops->unified)
+		if (type == CGROUP2_SUPER_MAGIC && !ops->unified) {
+			if (unprivileged)
+				cg_unified_delegate(&new->cgroup2_chown);
 			ops->unified = new;
+		}
 
 		continue;
 
@@ -2719,11 +2750,13 @@ static char *cg_unified_get_current_cgroup(bool relative)
 	return copy;
 }
 
-static int cg_unified_init(struct cgroup_ops *ops, bool relative)
+static int cg_unified_init(struct cgroup_ops *ops, bool relative,
+			   bool unprivileged)
 {
 	int ret;
-	char *mountpoint, *subtree_path;
+	char *mountpoint, *subtree_path, *tmp;
 	char **delegatable;
+	struct hierarchy *new;
 	char *base_cgroup = NULL;
 
 	ret = cg_is_pure_unified();
@@ -2759,7 +2792,9 @@ static int cg_unified_init(struct cgroup_ops *ops, bool relative)
 	 * controllers per container.
 	 */
 
-	add_hierarchy(&ops->hierarchies, delegatable, mountpoint, base_cgroup, CGROUP2_SUPER_MAGIC);
+	new = add_hierarchy(&ops->hierarchies, delegatable, mountpoint, base_cgroup, CGROUP2_SUPER_MAGIC);
+	if (!unprivileged)
+		cg_unified_delegate(&new->cgroup2_chown);
 
 	ops->cgroup_layout = CGROUP_LAYOUT_UNIFIED;
 	return CGROUP2_SUPER_MAGIC;
@@ -2785,14 +2820,14 @@ static bool cg_init(struct cgroup_ops *ops, struct lxc_conf *conf)
 		free(pin);
 	}
 
-	ret = cg_unified_init(ops, relative);
+	ret = cg_unified_init(ops, relative, !lxc_list_empty(&conf->id_map));
 	if (ret < 0)
 		return false;
 
 	if (ret == CGROUP2_SUPER_MAGIC)
 		return true;
 
-	return cg_hybrid_init(ops, relative);
+	return cg_hybrid_init(ops, relative, !lxc_list_empty(&conf->id_map));
 }
 
 __cgfsng_ops static bool cgfsng_data_init(struct cgroup_ops *ops)
diff --git a/src/lxc/cgroups/cgroup.c b/src/lxc/cgroups/cgroup.c
index f0d4e1eff..bf92bf298 100644
--- a/src/lxc/cgroups/cgroup.c
+++ b/src/lxc/cgroups/cgroup.c
@@ -82,12 +82,16 @@ void cgroup_exit(struct cgroup_ops *ops)
 	free(ops->container_cgroup);
 
 	for (it = ops->hierarchies; it && *it; it++) {
-		char **ctrlr;
+		char **p;
 
-		for (ctrlr = (*it)->controllers; ctrlr && *ctrlr; ctrlr++)
-			free(*ctrlr);
+		for (p = (*it)->controllers; p && *p; p++)
+			free(*p);
 		free((*it)->controllers);
 
+		for (p = (*it)->cgroup2_chown; p && *p; p++)
+			free(*p);
+		free((*it)->cgroup2_chown);
+
 		free((*it)->mountpoint);
 		free((*it)->container_base_path);
 		free((*it)->container_full_path);
diff --git a/src/lxc/cgroups/cgroup.h b/src/lxc/cgroups/cgroup.h
index d4dcd506b..b5d4c42bc 100644
--- a/src/lxc/cgroups/cgroup.h
+++ b/src/lxc/cgroups/cgroup.h
@@ -81,6 +81,11 @@ typedef enum {
  *   CGROUP2_SUPER_MAGIC.
  */
 struct hierarchy {
+	/*
+	 * cgroup2 only: what files need to be chowned to delegate a cgroup to
+	 * an unprivileged user.
+	 */
+	char **cgroup2_chown;
 	char **controllers;
 	char *mountpoint;
 	char *container_base_path;
diff --git a/src/lxc/lxccontainer.h b/src/lxc/lxccontainer.h
index c46be521e..2dfe4040b 100644
--- a/src/lxc/lxccontainer.h
+++ b/src/lxc/lxccontainer.h
@@ -867,6 +867,12 @@ struct lxc_container {
 	 */
 	int (*umount)(struct lxc_container *c, const char *target,
 		      unsigned long mountflags, struct lxc_mount *mnt);
+
+	/*!
+	 * \brief Get a file descriptor from the container.
+	 */
+	int (*ioctl)(struct lxc_container *c, unsigned int command,
+		     unsigned int flags, void *data);
 };
 
 /*!


More information about the lxc-devel mailing list