]> git.ipfire.org Git - thirdparty/lxc.git/commitdiff
lxc_unshare: Add uid_mapping when creating userns
authorMarcos Paulo de Souza <marcos.souza.org@gmail.com>
Wed, 29 Nov 2017 01:49:28 +0000 (23:49 -0200)
committerChristian Brauner <christian.brauner@ubuntu.com>
Sun, 17 Dec 2017 14:49:34 +0000 (15:49 +0100)
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#L286

Signed-off-by: Marcos Paulo de Souza <marcos.souza.org@gmail.com>
src/lxc/conf.c
src/lxc/conf.h
src/lxc/tools/lxc_unshare.c

index 898c728ad85107b6899ccb5a55f15acc61a2a3ce..03fae281c2fd9e8d0878d8dad517b398935e999d 100644 (file)
@@ -2342,7 +2342,7 @@ struct lxc_conf *lxc_conf_init(void)
        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)
 {
        char path[MAXPATHLEN];
index 85538a2397e0e83114eb912fd4bbfcbd483f8778..aa819da4d6577214bec46e4dae86dbd857c6f6a9 100644 (file)
@@ -287,6 +287,9 @@ struct lxc_conf {
        unsigned int ephemeral;
 };
 
+int write_id_mapping(enum idtype idtype, pid_t pid, const char *buf,
+                           size_t buf_size);
+
 #ifdef HAVE_TLS
 extern __thread struct lxc_conf *current_config;
 #else
index 843f663ed5ffd92ea405b5352f008e6b772b6589..59b8461a9a691fd29464c87099f120dc3bccf4fe 100644 (file)
@@ -31,6 +31,7 @@
 #include <signal.h>
 #include <stdlib.h>
 #include <string.h>
+#include <sys/eventfd.h>
 #include <sys/socket.h>
 #include <sys/types.h>
 #include <sys/wait.h>
@@ -93,24 +94,37 @@ static bool lookup_user(const char *optarg, uid_t *uid)
        return true;
 }
 
-
 struct start_arg {
        char ***args;
        int *flags;
        uid_t *uid;
        bool setuid;
        int want_default_mounts;
+       int wait_fd;
        const char *want_hostname;
 };
 
 static int do_start(void *arg)
 {
+       int ret;
+       uint64_t wait_val;
        struct start_arg *start_arg = arg;
        char **args = *start_arg->args;
        int flags = *start_arg->flags;
        uid_t uid = *start_arg->uid;
        int want_default_mounts = start_arg->want_default_mounts;
        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)
                lxc_setup_fs();
@@ -143,6 +157,7 @@ int main(int argc, char *argv[])
        int flags = 0, daemonize = 0;
        uid_t uid = 0; /* valid only if (flags & CLONE_NEWUSER) */
        pid_t pid;
+       uint64_t wait_val = 1;
        struct my_iflist *tmpif, *my_iflist = NULL;
        struct start_arg start_arg = {
                .args = &args,
@@ -241,12 +256,49 @@ int main(int argc, char *argv[])
                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);
        if (pid < 0) {
                fprintf(stderr, "failed to clone\n");
                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) {
                for (tmpif = my_iflist; tmpif; tmpif = tmpif->mi_next) {
                        if (lxc_netdev_move_by_name(tmpif->mi_ifname, pid, NULL) < 0)