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);
}
return move_ptr(entry);
}
-static struct lxc_list *get_minimal_idmap(const struct lxc_conf *conf)
+static struct lxc_list *get_minimal_idmap(const struct lxc_conf *conf,
+ uid_t *resuid, gid_t *resgid)
{
__do_free struct id_map *container_root_uid = NULL,
*container_root_gid = NULL,
/* idmap will now keep track of that memory. */
move_ptr(host_gid_map);
- TRACE("Allocated minimal idmapping");
+ TRACE("Allocated minimal idmapping for ns uid %d and ns gid %d", nsuid, nsgid);
+
+ if (resuid)
+ *resuid = nsuid;
+ if (resgid)
+ *resgid = nsgid;
return move_ptr(idmap);
}
if (!conf)
return -EINVAL;
- idmap = get_minimal_idmap(conf);
+ idmap = get_minimal_idmap(conf, NULL, NULL);
if (!idmap)
return ret_errno(ENOENT);
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;
+ uid_t resuid = LXC_INVALID_UID;
+ gid_t resgid = LXC_INVALID_GID;
char c = '1';
+ ssize_t ret;
pid_t pid;
int sock_fds[2];
- if (!conf)
- return -EINVAL;
+ if (!conf || !fn || !data)
+ return ret_errno(EINVAL);
- idmap = get_minimal_idmap(conf);
+ idmap = get_minimal_idmap(conf, &resuid, &resgid);
if (!idmap)
return ret_errno(ENOENT);
pid = fork();
if (pid < 0) {
- ERROR("Failed to clone process in new user namespace");
+ SYSERROR("Failed to create new process");
goto on_error;
}
close_prot_errno_disarm(sock_fds[1]);
ret = unshare(CLONE_NEWUSER);
- if (ret < 0)
+ if (ret < 0) {
+ SYSERROR("Failed to unshare new user namespace");
_exit(EXIT_FAILURE);
+ }
- rret = lxc_write_nointr(sock_fds[0], &c, 1);
- if (rret != 1)
+ ret = lxc_write_nointr(sock_fds[0], &c, 1);
+ if (ret != 1)
_exit(EXIT_FAILURE);
ret = lxc_read_nointr(sock_fds[0], &c, 1);
if (!lxc_setgroups(0, NULL) && errno != EPERM)
_exit(EXIT_FAILURE);
- if (!lxc_switch_uid_gid(0, 0))
+ ret = setresgid(resgid, resgid, resgid);
+ if (ret < 0) {
+ SYSERROR("Failed to setresgid(%d, %d, %d)",
+ resgid, resgid, resgid);
_exit(EXIT_FAILURE);
+ }
+
+ ret = setresuid(resuid, resuid, resuid);
+ if (ret < 0) {
+ SYSERROR("Failed to setresuid(%d, %d, %d)",
+ resuid, resuid, resuid);
+ _exit(EXIT_FAILURE);
+ }
ret = fn(data);
- if (ret)
+ if (ret) {
+ SYSERROR("Running function in new user namespace failed");
_exit(EXIT_FAILURE);
+ }
_exit(EXIT_SUCCESS);
}
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;
+ if (pid < 0)
+ return -1;
- return ret;
+ return wait_for_pid(pid);
}
int userns_exec_full(struct lxc_conf *conf, int (*fn)(void *), void *data,