From a19b974f42d4ceff13f605e5a7194502dee1dfa0 Mon Sep 17 00:00:00 2001 From: Christian Brauner 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 Cc: Felix Abecassis Cc: Jonathan Calmels Signed-off-by: Christian Brauner --- src/lxc/cgroups/cgfsng.c | 4 ++-- src/lxc/conf.c | 34 ++++++++++++++++++++++++++++++---- src/lxc/conf.h | 2 +- src/lxc/start.c | 2 +- 4 files changed, 34 insertions(+), 8 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/conf.h b/src/lxc/conf.h index 371238220..806a15733 100644 --- a/src/lxc/conf.h +++ b/src/lxc/conf.h @@ -410,7 +410,7 @@ struct lxc_conf { struct lxc_list procs; }; -int write_id_mapping(enum idtype idtype, pid_t pid, const char *buf, +extern int write_id_mapping(enum idtype idtype, pid_t pid, const char *buf, size_t buf_size); #ifdef HAVE_TLS 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) { -- 2.47.2