]> git.ipfire.org Git - thirdparty/lxc.git/commitdiff
lxc_unshare: Add uid_mapping when creating userns 1979/head
authorMarcos Paulo de Souza <marcos.souza.org@gmail.com>
Wed, 29 Nov 2017 01:49:28 +0000 (23:49 -0200)
committerMarcos Paulo de Souza <marcos.souza.org@gmail.com>
Fri, 1 Dec 2017 22:28:55 +0000 (20:28 -0200)
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 ae30b5b8726cf55cd737cba2adb2cb2e3d1c8f48..611b23a50ba0005566230feb3542b9ebf1ee5671 100644 (file)
@@ -2431,7 +2431,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 58302cf30c002bc9b1412a7b1d065b0c9c83a6de..f6c453a45a41329bff987be490c453829c50200b 100644 (file)
@@ -361,6 +361,9 @@ struct lxc_conf {
        char *inherit_ns[LXC_NS_MAX];
 };
 
+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 1b56d31b3e9de8cec56c4205bec6c396b86ce9ea..9e062a0ca7b068d3daf3dd489d6af2652c33c421 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)