[lxc-devel] [lxc/master] conf: write "deny" to /proc/[pid]/setgroups

brauner on Github lxc-bot at linuxcontainers.org
Wed Jan 3 17:21:49 UTC 2018


A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 947 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20180103/6841b40f/attachment.bin>
-------------- next part --------------
From 96eb79c3bad650b93587d8e9311c2eeda5c9de0a Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Wed, 3 Jan 2018 16:28:40 +0100
Subject: [PATCH] conf: write "deny" to /proc/[pid]/setgroups

When fully unprivileged users run a container that only maps their own {g,u}id
and they do not have access to setuid new{g,u}idmap binaries we will write the
idmapping directly. This however requires us to write "deny" to
/proc/[pid]/setgroups otherwise any write to /proc/[pid]/gid_map will be
denied.

On a sidenote, this patch enables fully unprivileged containers. If you now set
lxc.net.[i].type = empty no privilege whatsoever is required to run a container.

Enhances #2033.

Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
Cc: Felix Abecassis <fabecassis at nvidia.com>
Cc: Jonathan Calmels <jcalmels at nvidia.com>
---
 src/lxc/cgroups/cgfsng.c |  4 ++--
 src/lxc/conf.c           | 34 ++++++++++++++++++++++++++++++----
 src/lxc/start.c          |  2 +-
 3 files changed, 33 insertions(+), 7 deletions(-)

diff --git a/src/lxc/cgroups/cgfsng.c b/src/lxc/cgroups/cgfsng.c
index 28ddc827d..68520f4c8 100644
--- a/src/lxc/cgroups/cgfsng.c
+++ b/src/lxc/cgroups/cgfsng.c
@@ -1284,7 +1284,7 @@ static int rmdir_wrapper(void *data)
 		SYSERROR("Failed to setgid to 0");
 	if (setresuid(nsuid, nsuid, nsuid) < 0)
 		SYSERROR("Failed to setuid to 0");
-	if (setgroups(0, NULL) < 0)
+	if (setgroups(0, NULL) < 0 && errno != EPERM)
 		SYSERROR("Failed to clear groups");
 
 	return cgroup_rmdir(arg->path);
@@ -1481,7 +1481,7 @@ static int chown_cgroup_wrapper(void *data)
 		SYSERROR("Failed to setgid to 0");
 	if (setresuid(nsuid, nsuid, nsuid) < 0)
 		SYSERROR("Failed to setuid to 0");
-	if (setgroups(0, NULL) < 0)
+	if (setgroups(0, NULL) < 0 && errno != EPERM)
 		SYSERROR("Failed to clear groups");
 
 	destuid = get_ns_uid(arg->origuid);
diff --git a/src/lxc/conf.c b/src/lxc/conf.c
index 9a0360907..1f303454a 100644
--- a/src/lxc/conf.c
+++ b/src/lxc/conf.c
@@ -2627,28 +2627,54 @@ struct lxc_conf *lxc_conf_init(void)
 }
 
 int write_id_mapping(enum idtype idtype, pid_t pid, const char *buf,
-			    size_t buf_size)
+		     size_t buf_size)
 {
 	char path[MAXPATHLEN];
 	int fd, ret;
 
+	if (geteuid() != 0 && idtype == ID_TYPE_GID) {
+		size_t buflen;
+
+		ret = snprintf(path, MAXPATHLEN, "/proc/%d/setgroups", pid);
+		if (ret < 0 || ret >= MAXPATHLEN) {
+			ERROR("Failed to create string");
+			return -E2BIG;
+		}
+
+		fd = open(path, O_WRONLY);
+		if (fd < 0 && errno != ENOENT) {
+			SYSERROR("Failed to open \"%s\"", path);
+			return -1;
+		}
+
+		buflen = sizeof("deny\n") - 1;
+		errno = 0;
+		ret = lxc_write_nointr(fd, "deny\n", buflen);
+		if (ret != buflen) {
+			SYSERROR("Failed to write \"deny\" to \"/proc/%d/setgroups\"", pid);
+			close(fd);
+			return -1;
+		}
+		close(fd);
+	}
+
 	ret = snprintf(path, MAXPATHLEN, "/proc/%d/%cid_map", pid,
 		       idtype == ID_TYPE_UID ? 'u' : 'g');
 	if (ret < 0 || ret >= MAXPATHLEN) {
-		ERROR("failed to create path \"%s\"", path);
+		ERROR("Failed to create string");
 		return -E2BIG;
 	}
 
 	fd = open(path, O_WRONLY);
 	if (fd < 0) {
-		SYSERROR("failed to open \"%s\"", path);
+		SYSERROR("Failed to open \"%s\"", path);
 		return -1;
 	}
 
 	errno = 0;
 	ret = lxc_write_nointr(fd, buf, buf_size);
 	if (ret != buf_size) {
-		SYSERROR("failed to write %cid mapping to \"%s\"",
+		SYSERROR("Failed to write %cid mapping to \"%s\"",
 			 idtype == ID_TYPE_UID ? 'u' : 'g', path);
 		close(fd);
 		return -1;
diff --git a/src/lxc/start.c b/src/lxc/start.c
index d5b6f56e7..e2ca11455 100644
--- a/src/lxc/start.c
+++ b/src/lxc/start.c
@@ -1014,7 +1014,7 @@ static int do_start(void *data)
 		 * user namespace.
 		 */
 		ret = lxc_setgroups(0, NULL);
-		if (ret < 0)
+		if (ret < 0 && (handler->am_root || errno != EPERM))
 			goto out_warn_father;
 
 		if (!handler->am_root) {


More information about the lxc-devel mailing list