[lxc-devel] [lxc/master] attach: fixes

brauner on Github lxc-bot at linuxcontainers.org
Fri Mar 27 19:12:35 UTC 2020


A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 364 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20200327/b698591a/attachment-0001.bin>
-------------- next part --------------
From 4b86fefd0f4afff5a3c97a2bb8817ce34d646478 Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Fri, 27 Mar 2020 19:46:10 +0100
Subject: [PATCH 1/2] Revert "cgroups: fix unified cgroup attach"

This reverts commit ba7ca43b0be417275db7865336191681d915e97c.

Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
 src/lxc/cgroups/cgfsng.c | 100 ++++++++++++++++++++++++---------------
 1 file changed, 63 insertions(+), 37 deletions(-)

diff --git a/src/lxc/cgroups/cgfsng.c b/src/lxc/cgroups/cgfsng.c
index 7a2a4314be..42cef8831a 100644
--- a/src/lxc/cgroups/cgfsng.c
+++ b/src/lxc/cgroups/cgfsng.c
@@ -2057,11 +2057,8 @@ static inline char *build_full_cgpath_from_monitorpath(struct hierarchy *h,
 	return must_make_path(h->mountpoint, inpath, filename, NULL);
 }
 
-#define LXC_UNIFIED_ATTACH_CGROUP_LEN STRLITERALLEN("/lxc-1000/cgroup.procs")
-static int cgroup_attach_leaf(const struct lxc_conf *conf, char *unified_path,
-			      int unified_fd, pid_t pid)
+static int cgroup_attach_leaf(const struct lxc_conf *conf, int unified_fd, pid_t pid)
 {
-	__do_free char *path = NULL;
 	int idx = 1;
 	int ret;
 	char pidstr[INTTYPE_TO_STRLEN(int64_t) + 1];
@@ -2072,11 +2069,6 @@ static int cgroup_attach_leaf(const struct lxc_conf *conf, char *unified_path,
 	if (ret < 0 && errno != EEXIST)
 		return log_error_errno(-1, errno, "Failed to create leaf cgroup \"lxc\"");
 
-	path = must_make_path(unified_path, "lxc", NULL);
-	ret = chown_mapped_root(path, conf);
-	if (ret < 0)
-		return log_error_errno(-1, errno, "Failed to chown \"%s\"", path);
-
 	pidstr_len = sprintf(pidstr, INT64_FMT, (int64_t)pid);
 	ret = lxc_writeat(unified_fd, "lxc/cgroup.procs", pidstr, pidstr_len);
 	if (ret < 0)
@@ -2088,10 +2080,9 @@ static int cgroup_attach_leaf(const struct lxc_conf *conf, char *unified_path,
 	if (errno != EBUSY)
 		return log_error_errno(-1, errno, "Failed to attach to unified cgroup");
 
-	free_disarm(path);
 	do {
 		bool rm = false;
-		char attach_cgroup[LXC_UNIFIED_ATTACH_CGROUP_LEN + 1];
+		char attach_cgroup[STRLITERALLEN("lxc-1000/cgroup.procs") + 1];
 		char *slash;
 
 		sprintf(attach_cgroup, "lxc-%d/cgroup.procs", idx);
@@ -2106,12 +2097,6 @@ static int cgroup_attach_leaf(const struct lxc_conf *conf, char *unified_path,
 
 		*slash = '/';
 
-		path = must_make_path(unified_path, attach_cgroup, NULL);
-		ret = chown_mapped_root(path, conf);
-		if (ret < 0)
-			return log_error_errno(-1, errno, "Failed to chown \"%s\"", path);
-		free_disarm(path);
-
 		ret = lxc_writeat(unified_fd, attach_cgroup, pidstr, pidstr_len);
 		if (ret == 0)
 			return 0;
@@ -2129,14 +2114,46 @@ static int cgroup_attach_leaf(const struct lxc_conf *conf, char *unified_path,
 	return log_error_errno(-1, errno, "Failed to attach to unified cgroup");
 }
 
+struct userns_exec_unified_attach_data {
+	const struct lxc_conf *conf;
+	int unified_fd;
+	pid_t pid;
+};
+
+static int cgroup_unified_attach_wrapper(void *data)
+{
+	struct userns_exec_unified_attach_data *args = data;
+	uid_t nsuid;
+	gid_t nsgid;
+	int ret;
+
+	if (!args->conf || args->unified_fd < 0 || args->pid <= 0)
+		return ret_errno(EINVAL);
+
+	if (!lxc_setgroups(0, NULL) && errno != EPERM)
+		return log_error_errno(-1, errno, "Failed to setgroups(0, NULL)");
+
+	nsuid = (args->conf->root_nsuid_map != NULL) ? 0 : args->conf->init_uid;
+	nsgid = (args->conf->root_nsgid_map != NULL) ? 0 : args->conf->init_gid;
+
+	ret = setresgid(nsgid, nsgid, nsgid);
+	if (ret < 0)
+		return log_error_errno(-1, errno, "Failed to setresgid(%d, %d, %d)",
+				       (int)nsgid, (int)nsgid, (int)nsgid);
+
+	ret = setresuid(nsuid, nsuid, nsuid);
+	if (ret < 0)
+		return log_error_errno(-1, errno, "Failed to setresuid(%d, %d, %d)",
+				       (int)nsuid, (int)nsuid, (int)nsuid);
+
+	return cgroup_attach_leaf(args->conf, args->unified_fd, args->pid);
+}
+
 int cgroup_attach(const struct lxc_conf *conf, const char *name,
 		  const char *lxcpath, pid_t pid)
 {
 	__do_close int unified_fd = -EBADF;
-	__do_free char *buf = NULL;
 	int ret;
-	ssize_t len;
-	struct stat st;
 
 	if (!conf || !name || !lxcpath || pid <= 0)
 		return ret_errno(EINVAL);
@@ -2145,24 +2162,20 @@ int cgroup_attach(const struct lxc_conf *conf, const char *name,
 	if (unified_fd < 0)
 		return ret_errno(EBADF);
 
-	ret = fstatat(unified_fd, "", &st, AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW);
-	if (ret < 0)
-		return -errno;
-
-	if (st.st_size == 0)
-		return ret_errno(EINVAL);
-
-	buf = zalloc(st.st_size);
-	if (!buf)
-		return ret_errno(ENOMEM);
+	if (!lxc_list_empty(&conf->id_map)) {
+		struct userns_exec_unified_attach_data args = {
+			.conf		= conf,
+			.unified_fd	= unified_fd,
+			.pid		= pid,
+		};
 
-	len = readlinkat(unified_fd, "", buf, st.st_size);
-	if (len < 0)
-		return -errno;
-	if (len >= st.st_size)
-		return ret_errno(E2BIG);
+		ret = userns_exec_1(conf, cgroup_unified_attach_wrapper, &args,
+				    "cgroup_unified_attach_wrapper");
+	} else {
+		ret = cgroup_attach_leaf(conf, unified_fd, pid);
+	}
 
-	return cgroup_attach_leaf(conf, buf, unified_fd, pid);
+	return ret;
 }
 
 /* Technically, we're always at a delegation boundary here (This is especially
@@ -2204,7 +2217,20 @@ static int __cg_unified_attach(const struct hierarchy *h,
 	if (unified_fd < 0)
 		return ret_errno(EBADF);
 
-	return cgroup_attach_leaf(conf, path, unified_fd, pid);
+	if (!lxc_list_empty(&conf->id_map)) {
+		struct userns_exec_unified_attach_data args = {
+			.conf		= conf,
+			.unified_fd	= unified_fd,
+			.pid		= pid,
+		};
+
+		ret = userns_exec_1(conf, cgroup_unified_attach_wrapper, &args,
+				    "cgroup_unified_attach_wrapper");
+	} else {
+		ret = cgroup_attach_leaf(conf, unified_fd, pid);
+	}
+
+	return ret;
 }
 
 __cgfsng_ops static bool cgfsng_attach(struct cgroup_ops *ops,

From edf88289124a7c5d9995e551973d4eae32daafa2 Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Fri, 27 Mar 2020 20:11:41 +0100
Subject: [PATCH 2/2] conf: introduce and use userns_exec_minimal()

Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
 src/lxc/cgroups/cgfsng.c |   6 +--
 src/lxc/conf.c           | 104 +++++++++++++++++++++++++++++++++++++++
 src/lxc/conf.h           |   1 +
 3 files changed, 107 insertions(+), 4 deletions(-)

diff --git a/src/lxc/cgroups/cgfsng.c b/src/lxc/cgroups/cgfsng.c
index 42cef8831a..8563ed7d27 100644
--- a/src/lxc/cgroups/cgfsng.c
+++ b/src/lxc/cgroups/cgfsng.c
@@ -2169,8 +2169,7 @@ int cgroup_attach(const struct lxc_conf *conf, const char *name,
 			.pid		= pid,
 		};
 
-		ret = userns_exec_1(conf, cgroup_unified_attach_wrapper, &args,
-				    "cgroup_unified_attach_wrapper");
+		ret = userns_exec_minimal(conf, cgroup_unified_attach_wrapper, &args);
 	} else {
 		ret = cgroup_attach_leaf(conf, unified_fd, pid);
 	}
@@ -2224,8 +2223,7 @@ static int __cg_unified_attach(const struct hierarchy *h,
 			.pid		= pid,
 		};
 
-		ret = userns_exec_1(conf, cgroup_unified_attach_wrapper, &args,
-				    "cgroup_unified_attach_wrapper");
+		ret = userns_exec_minimal(conf, cgroup_unified_attach_wrapper, &args);
 	} else {
 		ret = cgroup_attach_leaf(conf, unified_fd, pid);
 	}
diff --git a/src/lxc/conf.c b/src/lxc/conf.c
index edcc8cbf03..9e106b1006 100644
--- a/src/lxc/conf.c
+++ b/src/lxc/conf.c
@@ -4120,6 +4120,110 @@ int userns_exec_1(const struct lxc_conf *conf, int (*fn)(void *), void *data,
 	return ret;
 }
 
+int userns_exec_minimal(const struct lxc_conf *conf, int (*fn)(void *), void *data)
+{
+	call_cleaner(lxc_free_idmap) struct lxc_list *idmap = NULL;
+	int ret = -1, status = -1;
+	ssize_t rret;
+	char c = '1';
+	pid_t pid;
+	int sock_fds[2];
+
+	if (!conf)
+		return -EINVAL;
+
+	idmap = get_minimal_idmap(conf);
+	if (!idmap)
+		return ret_errno(ENOENT);
+
+	ret = socketpair(PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0, sock_fds);
+	if (ret < 0)
+		return -errno;
+
+	pid = fork();
+	if (pid < 0) {
+		ERROR("Failed to clone process in new user namespace");
+		goto on_error;
+	}
+
+	if (pid == 0) {
+		close_prot_errno_disarm(sock_fds[1]);
+
+		ret = unshare(CLONE_NEWUSER);
+		if (ret < 0)
+			_exit(EXIT_FAILURE);
+
+		rret = lxc_write_nointr(sock_fds[0], &c, 1);
+		if (rret != 1)
+			_exit(EXIT_FAILURE);
+
+		ret = lxc_read_nointr(sock_fds[0], &c, 1);
+		if (ret != 1)
+			_exit(EXIT_FAILURE);
+
+		close_prot_errno_disarm(sock_fds[0]);
+
+		if (!lxc_setgroups(0, NULL) && errno != EPERM)
+			_exit(EXIT_FAILURE);
+
+		if (!lxc_switch_uid_gid(0, 0))
+			_exit(EXIT_FAILURE);
+
+		ret = fn(data);
+		if (ret)
+			_exit(EXIT_FAILURE);
+
+		_exit(EXIT_SUCCESS);
+	}
+
+	close_prot_errno_disarm(sock_fds[0]);
+
+	if (lxc_log_get_level() == LXC_LOG_LEVEL_TRACE ||
+	    conf->loglevel == LXC_LOG_LEVEL_TRACE) {
+		struct id_map *map;
+		struct lxc_list *it;
+
+		lxc_list_for_each(it, idmap) {
+			map = it->elem;
+			TRACE("Establishing %cid mapping for \"%d\" in new user namespace: nsuid %lu - hostid %lu - range %lu",
+			      (map->idtype == ID_TYPE_UID) ? 'u' : 'g', pid, map->nsid, map->hostid, map->range);
+		}
+	}
+
+	ret = lxc_read_nointr(sock_fds[1], &c, 1);
+	if (ret != 1) {
+		SYSERROR("Failed waiting for child process %d\" to tell us to proceed", pid);
+		goto on_error;
+	}
+
+	/* Set up {g,u}id mapping for user namespace of child process. */
+	ret = lxc_map_ids(idmap, pid);
+	if (ret < 0) {
+		ERROR("Error setting up {g,u}id mappings for child process \"%d\"", pid);
+		goto on_error;
+	}
+
+	/* Tell child to proceed. */
+	ret = lxc_write_nointr(sock_fds[1], &c, 1);
+	if (ret != 1) {
+		SYSERROR("Failed telling child process \"%d\" to proceed", pid);
+		goto on_error;
+	}
+
+on_error:
+	close_prot_errno_disarm(sock_fds[0]);
+	close_prot_errno_disarm(sock_fds[1]);
+
+	/* Wait for child to finish. */
+	if (pid > 0)
+		status = wait_for_pid(pid);
+
+	if (status < 0)
+		ret = -1;
+
+	return ret;
+}
+
 int userns_exec_full(struct lxc_conf *conf, int (*fn)(void *), void *data,
 		     const char *fn_name)
 {
diff --git a/src/lxc/conf.h b/src/lxc/conf.h
index f37e09e4af..2bd2a203a6 100644
--- a/src/lxc/conf.h
+++ b/src/lxc/conf.h
@@ -467,5 +467,6 @@ extern int setup_proc_filesystem(struct lxc_list *procs, pid_t pid);
 extern int lxc_clear_procs(struct lxc_conf *c, const char *key);
 extern int lxc_clear_apparmor_raw(struct lxc_conf *c);
 extern int lxc_clear_namespace(struct lxc_conf *c);
+extern int userns_exec_minimal(const struct lxc_conf *conf, int (*fn)(void *), void *data);
 
 #endif /* __LXC_CONF_H */


More information about the lxc-devel mailing list