Unverified Commit 28f7670c by Marcos Paulo de Souza Committed by Christian Brauner

lxc_unshare: Add uid_mapping when creating userns

Change conf.c to export function write_id_mapping, which will now be called inside main function of lxc_unshare.c. This is required because setuid syscalls only permits a new userns to set a new uid if the uid of parameter is mapped inside the ns using uid_map file[1]. So, just after the clone invocation, map the uid passed as parameter into the newly created user namespace, and put the current uid as the ID-outside-ns. After the mapping is done, setuid call succeeds. Closes: #494 [1] https://elixir.free-electrons.com/linux/latest/source/kernel/user_namespace.c#L286Signed-off-by: 's avatarMarcos Paulo de Souza <marcos.souza.org@gmail.com>
parent eb59c469
...@@ -2427,7 +2427,7 @@ struct lxc_conf *lxc_conf_init(void) ...@@ -2427,7 +2427,7 @@ struct lxc_conf *lxc_conf_init(void)
return new; return new;
} }
static 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];
......
...@@ -343,6 +343,9 @@ struct lxc_conf { ...@@ -343,6 +343,9 @@ struct lxc_conf {
struct lxc_cgroup cgroup_meta; struct lxc_cgroup cgroup_meta;
}; };
int write_id_mapping(enum idtype idtype, pid_t pid, const char *buf,
size_t buf_size);
#ifdef HAVE_TLS #ifdef HAVE_TLS
extern __thread struct lxc_conf *current_config; extern __thread struct lxc_conf *current_config;
#else #else
......
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
#include <signal.h> #include <signal.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <sys/eventfd.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/wait.h> #include <sys/wait.h>
...@@ -93,24 +94,37 @@ static bool lookup_user(const char *optarg, uid_t *uid) ...@@ -93,24 +94,37 @@ static bool lookup_user(const char *optarg, uid_t *uid)
return true; return true;
} }
struct start_arg { struct start_arg {
char ***args; char ***args;
int *flags; int *flags;
uid_t *uid; uid_t *uid;
bool setuid; bool setuid;
int want_default_mounts; int want_default_mounts;
int wait_fd;
const char *want_hostname; const char *want_hostname;
}; };
static int do_start(void *arg) static int do_start(void *arg)
{ {
int ret;
uint64_t wait_val;
struct start_arg *start_arg = arg; struct start_arg *start_arg = arg;
char **args = *start_arg->args; char **args = *start_arg->args;
int flags = *start_arg->flags; int flags = *start_arg->flags;
uid_t uid = *start_arg->uid; uid_t uid = *start_arg->uid;
int want_default_mounts = start_arg->want_default_mounts; int want_default_mounts = start_arg->want_default_mounts;
const char *want_hostname = start_arg->want_hostname; const char *want_hostname = start_arg->want_hostname;
int wait_fd = start_arg->wait_fd;
if (start_arg->setuid) {
/* waiting until uid maps is set */
ret = read(wait_fd, &wait_val, sizeof(wait_val));
if (ret == -1) {
close(wait_fd);
fprintf(stderr, "read eventfd failed\n");
exit(EXIT_FAILURE);
}
}
if ((flags & CLONE_NEWNS) && want_default_mounts) if ((flags & CLONE_NEWNS) && want_default_mounts)
lxc_setup_fs(); lxc_setup_fs();
...@@ -143,6 +157,7 @@ int main(int argc, char *argv[]) ...@@ -143,6 +157,7 @@ int main(int argc, char *argv[])
int flags = 0, daemonize = 0; int flags = 0, daemonize = 0;
uid_t uid = 0; /* valid only if (flags & CLONE_NEWUSER) */ uid_t uid = 0; /* valid only if (flags & CLONE_NEWUSER) */
pid_t pid; pid_t pid;
uint64_t wait_val = 1;
struct my_iflist *tmpif, *my_iflist = NULL; struct my_iflist *tmpif, *my_iflist = NULL;
struct start_arg start_arg = { struct start_arg start_arg = {
.args = &args, .args = &args,
...@@ -241,12 +256,49 @@ int main(int argc, char *argv[]) ...@@ -241,12 +256,49 @@ int main(int argc, char *argv[])
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
if (start_arg.setuid) {
start_arg.wait_fd = eventfd(0, EFD_CLOEXEC);
if (start_arg.wait_fd < 0) {
fprintf(stderr, "failed to create eventfd\n");
exit(EXIT_FAILURE);
}
}
pid = lxc_clone(do_start, &start_arg, flags); pid = lxc_clone(do_start, &start_arg, flags);
if (pid < 0) { if (pid < 0) {
fprintf(stderr, "failed to clone\n"); fprintf(stderr, "failed to clone\n");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
if (start_arg.setuid) {
/* enough space to accommodate uids */
char *umap = (char *)alloca(100);
/* create new uid mapping using current UID and the one
* specified as parameter
*/
ret = snprintf(umap, 100, "%d %d 1\n" , *(start_arg.uid), getuid());
if (ret < 0 || ret >= 100) {
close(start_arg.wait_fd);
fprintf(stderr, "snprintf failed");
exit(EXIT_FAILURE);
}
ret = write_id_mapping(ID_TYPE_UID, pid, umap, strlen(umap));
if (ret < 0) {
close(start_arg.wait_fd);
fprintf(stderr, "uid mapping failed\n");
exit(EXIT_FAILURE);
}
ret = write(start_arg.wait_fd, &wait_val, sizeof(wait_val));
if (ret < 0) {
close(start_arg.wait_fd);
fprintf(stderr, "write to eventfd failed\n");
exit(EXIT_FAILURE);
}
}
if (my_iflist) { if (my_iflist) {
for (tmpif = my_iflist; tmpif; tmpif = tmpif->mi_next) { for (tmpif = my_iflist; tmpif; tmpif = tmpif->mi_next) {
if (lxc_netdev_move_by_name(tmpif->mi_ifname, pid, NULL) < 0) if (lxc_netdev_move_by_name(tmpif->mi_ifname, pid, NULL) < 0)
......
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