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: 's avatarChristian Brauner <christian.brauner@ubuntu.com> Cc: Felix Abecassis <fabecassis@nvidia.com> Cc: Jonathan Calmels <jcalmels@nvidia.com> Signed-off-by: 's avatarChristian Brauner <christian.brauner@ubuntu.com>
parent fd7374db
...@@ -1284,7 +1284,7 @@ static int rmdir_wrapper(void *data) ...@@ -1284,7 +1284,7 @@ static int rmdir_wrapper(void *data)
SYSERROR("Failed to setgid to 0"); SYSERROR("Failed to setgid to 0");
if (setresuid(nsuid, nsuid, nsuid) < 0) if (setresuid(nsuid, nsuid, nsuid) < 0)
SYSERROR("Failed to setuid to 0"); SYSERROR("Failed to setuid to 0");
if (setgroups(0, NULL) < 0) if (setgroups(0, NULL) < 0 && errno != EPERM)
SYSERROR("Failed to clear groups"); SYSERROR("Failed to clear groups");
return cgroup_rmdir(arg->path); return cgroup_rmdir(arg->path);
...@@ -1481,7 +1481,7 @@ static int chown_cgroup_wrapper(void *data) ...@@ -1481,7 +1481,7 @@ static int chown_cgroup_wrapper(void *data)
SYSERROR("Failed to setgid to 0"); SYSERROR("Failed to setgid to 0");
if (setresuid(nsuid, nsuid, nsuid) < 0) if (setresuid(nsuid, nsuid, nsuid) < 0)
SYSERROR("Failed to setuid to 0"); SYSERROR("Failed to setuid to 0");
if (setgroups(0, NULL) < 0) if (setgroups(0, NULL) < 0 && errno != EPERM)
SYSERROR("Failed to clear groups"); SYSERROR("Failed to clear groups");
destuid = get_ns_uid(arg->origuid); destuid = get_ns_uid(arg->origuid);
......
...@@ -2627,28 +2627,54 @@ struct lxc_conf *lxc_conf_init(void) ...@@ -2627,28 +2627,54 @@ struct lxc_conf *lxc_conf_init(void)
} }
int write_id_mapping(enum idtype idtype, pid_t pid, const char *buf, int write_id_mapping(enum idtype idtype, pid_t pid, const char *buf,
size_t buf_size) size_t buf_size)
{ {
char path[MAXPATHLEN]; char path[MAXPATHLEN];
int fd, ret; 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, ret = snprintf(path, MAXPATHLEN, "/proc/%d/%cid_map", pid,
idtype == ID_TYPE_UID ? 'u' : 'g'); idtype == ID_TYPE_UID ? 'u' : 'g');
if (ret < 0 || ret >= MAXPATHLEN) { if (ret < 0 || ret >= MAXPATHLEN) {
ERROR("failed to create path \"%s\"", path); ERROR("Failed to create string");
return -E2BIG; return -E2BIG;
} }
fd = open(path, O_WRONLY); fd = open(path, O_WRONLY);
if (fd < 0) { if (fd < 0) {
SYSERROR("failed to open \"%s\"", path); SYSERROR("Failed to open \"%s\"", path);
return -1; return -1;
} }
errno = 0; errno = 0;
ret = lxc_write_nointr(fd, buf, buf_size); ret = lxc_write_nointr(fd, buf, buf_size);
if (ret != 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); idtype == ID_TYPE_UID ? 'u' : 'g', path);
close(fd); close(fd);
return -1; return -1;
......
...@@ -410,7 +410,7 @@ struct lxc_conf { ...@@ -410,7 +410,7 @@ struct lxc_conf {
struct lxc_list procs; 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); size_t buf_size);
#ifdef HAVE_TLS #ifdef HAVE_TLS
......
...@@ -1014,7 +1014,7 @@ static int do_start(void *data) ...@@ -1014,7 +1014,7 @@ static int do_start(void *data)
* user namespace. * user namespace.
*/ */
ret = lxc_setgroups(0, NULL); ret = lxc_setgroups(0, NULL);
if (ret < 0) if (ret < 0 && (handler->am_root || errno != EPERM))
goto out_warn_father; goto out_warn_father;
if (!handler->am_root) { if (!handler->am_root) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment