]> git.proxmox.com Git - mirror_lxc.git/commitdiff
attach: handle id switching smarter
authorChristian Brauner <christian.brauner@ubuntu.com>
Sun, 9 Sep 2018 11:20:14 +0000 (13:20 +0200)
committerChristian Brauner <christian.brauner@ubuntu.com>
Tue, 11 Sep 2018 08:54:44 +0000 (10:54 +0200)
For setup, switch to the most privileged ids we can find. That is either
nsuid 0 if a mapping has been established if not switch to the ids the
init running in the container was started with.
After setup, switch to the actual requested ids.

Closes #2591.

Signed-off-by: Christian Brauner <christian.brauner@ubuntu.com>
src/lxc/attach.c

index 87f14398f5926f9da4d03699b4278c995e155ad9..8387bbfe174a38b5537eaebaabd17312c9937f2e 100644 (file)
@@ -749,6 +749,8 @@ static int attach_child_main(struct attach_clone_payload *payload)
        int fd, lsm_fd, ret;
        uid_t new_uid;
        gid_t new_gid;
+       uid_t ns_root_uid = 0;
+       gid_t ns_root_gid = 0;
        lxc_attach_options_t* options = payload->options;
        struct lxc_proc_context_info* init_ctx = payload->init_ctx;
        bool needs_lsm = (options->namespaces & CLONE_NEWNS) &&
@@ -836,25 +838,23 @@ static int attach_child_main(struct attach_clone_payload *payload)
                        goto on_error;
        }
 
-       /* Set {u,g}id. */
-       new_uid = 0;
-       new_gid = 0;
+       if (options->namespaces & CLONE_NEWUSER) {
+               /* Check whether nsuid 0 has a mapping. */
+               ns_root_uid = get_ns_uid(0);
 
-       /* Ignore errors, we will fall back to root in that case (/proc was not
-        * mounted etc.).
-        */
-       if (options->namespaces & CLONE_NEWUSER)
-               lxc_attach_get_init_uidgid(&new_uid, &new_gid);
+               /* Check whether nsgid 0 has a mapping. */
+               ns_root_gid = get_ns_gid(0);
 
-       if (options->uid != (uid_t)-1)
-               new_uid = options->uid;
+               /* If there's no mapping for nsuid 0 try to retrieve the nsuid
+                * init was started with.
+                */
+               if (ns_root_uid == LXC_INVALID_UID)
+                       lxc_attach_get_init_uidgid(&ns_root_uid, &ns_root_gid);
 
-       if (options->gid != (gid_t)-1)
-               new_gid = options->gid;
+               if (ns_root_uid == LXC_INVALID_UID)
+                       goto on_error;
 
-       /* Try to set the {u,g}id combination. */
-       if (new_uid != 0 || new_gid != 0 || options->namespaces & CLONE_NEWUSER) {
-               ret = lxc_switch_uid_gid(new_uid, new_gid);
+               ret = lxc_switch_uid_gid(ns_root_uid, ns_root_gid);
                if (ret < 0)
                        goto on_error;
        }
@@ -863,6 +863,17 @@ static int attach_child_main(struct attach_clone_payload *payload)
        if (ret < 0 && errno != EPERM)
                goto on_error;
 
+       /* Set {u,g}id. */
+       if (options->uid != LXC_INVALID_UID)
+               new_uid = options->uid;
+       else
+               new_uid = ns_root_uid;
+
+       if (options->gid != LXC_INVALID_GID)
+               new_gid = options->gid;
+       else
+               new_gid = ns_root_gid;
+
        if ((init_ctx->container && init_ctx->container->lxc_conf &&
             init_ctx->container->lxc_conf->no_new_privs) ||
            (options->attach_flags & LXC_ATTACH_NO_NEW_PRIVS)) {
@@ -952,6 +963,17 @@ static int attach_child_main(struct attach_clone_payload *payload)
                TRACE("Prepared terminal file descriptor %d", payload->terminal_slave_fd);
        }
 
+       /* Avoid unnecessary syscalls. */
+       if (new_uid == ns_root_uid)
+               new_uid = LXC_INVALID_UID;
+
+       if (new_gid == ns_root_gid)
+               new_gid = LXC_INVALID_GID;
+
+       ret = lxc_switch_uid_gid(new_uid, new_gid);
+       if (ret < 0)
+               goto on_error;
+
        /* We're done, so we can now do whatever the user intended us to do. */
        _exit(payload->exec_function(payload->exec_payload));