]> git.ipfire.org Git - thirdparty/lxc.git/commitdiff
attach: improve id switching
authorChristian Brauner <christian.brauner@ubuntu.com>
Tue, 9 Apr 2019 17:42:43 +0000 (19:42 +0200)
committerChristian Brauner <christian.brauner@ubuntu.com>
Tue, 9 Apr 2019 17:51:36 +0000 (19:51 +0200)
Signed-off-by: Christian Brauner <christian.brauner@ubuntu.com>
src/lxc/attach.c
src/lxc/utils.c
src/lxc/utils.h

index 08bb48affdcc99ce4dfc1c41623c93d46ecfbf80..d4590468c70f94c607211e5c478590063d884185 100644 (file)
@@ -726,6 +726,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) &&
@@ -809,25 +811,40 @@ static int attach_child_main(struct attach_clone_payload *payload)
        /* 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);
+       if (options->namespaces & CLONE_NEWUSER) {
+               /* Check whether nsuid 0 has a mapping. */
+               ns_root_uid = get_ns_uid(0);
 
-       if (options->uid != (uid_t)-1)
-               new_uid = options->uid;
-       if (options->gid != (gid_t)-1)
-               new_gid = options->gid;
+               /* Check whether nsgid 0 has a mapping. */
+               ns_root_gid = get_ns_gid(0);
 
-       /* 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);
-               if (ret < 0)
+               /* 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 (ns_root_uid == LXC_INVALID_UID)
                        goto on_error;
 
-               ret = lxc_setgroups(0, NULL);
-               if (ret < 0)
+               if (!lxc_switch_uid_gid(ns_root_uid, ns_root_gid))
                        goto on_error;
        }
 
+       if (!lxc_setgroups(0, NULL) && 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 (needs_lsm) {
                bool on_exec;
 
@@ -909,6 +926,16 @@ static int attach_child_main(struct attach_clone_payload *payload)
                TRACE("Prepared pty file descriptor %d", payload->pty_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;
+
+       if (!lxc_switch_uid_gid(new_uid, new_gid))
+               goto on_error;
+
        /* We're done, so we can now do whatever the user intended us to do. */
        rexit(payload->exec_function(payload->exec_payload));
 
index 8d315038e206e28629de68aaded87ceb1d8bc5eb..e0f49bcb6bcea77b4ac62d388a7a62dbb6330b55 100644 (file)
@@ -1001,17 +1001,18 @@ void **lxc_append_null_to_array(void **array, size_t count)
 
 int randseed(bool srand_it)
 {
+       FILE *f;
        /*
-          srand pre-seed function based on /dev/urandom
-          */
+        * srand pre-seed function based on /dev/urandom
+        */
        unsigned int seed = time(NULL) + getpid();
 
-       FILE *f;
        f = fopen("/dev/urandom", "r");
        if (f) {
                int ret = fread(&seed, sizeof(seed), 1, f);
                if (ret != 1)
-                       DEBUG("unable to fread /dev/urandom, %s, fallback to time+pid rand seed", strerror(errno));
+                       SYSDEBUG("Unable to fread /dev/urandom, fallback to time+pid rand seed");
+
                fclose(f);
        }
 
@@ -1026,26 +1027,62 @@ uid_t get_ns_uid(uid_t orig)
        char *line = NULL;
        size_t sz = 0;
        uid_t nsid, hostid, range;
-       FILE *f = fopen("/proc/self/uid_map", "r");
-       if (!f)
+       FILE *f;
+
+       f = fopen("/proc/self/uid_map", "r");
+       if (!f) {
+               SYSERROR("Failed to open uid_map");
                return 0;
+       }
 
        while (getline(&line, &sz, f) != -1) {
                if (sscanf(line, "%u %u %u", &nsid, &hostid, &range) != 3)
                        continue;
+
                if (hostid <= orig && hostid + range > orig) {
                        nsid += orig - hostid;
                        goto found;
                }
        }
 
-       nsid = 0;
+       nsid = LXC_INVALID_UID;
+
 found:
        fclose(f);
        free(line);
        return nsid;
 }
 
+gid_t get_ns_gid(gid_t orig)
+{
+       char *line = NULL;
+       size_t sz = 0;
+       gid_t nsid, hostid, range;
+       FILE *f;
+
+       f = fopen("/proc/self/gid_map", "r");
+       if (!f) {
+               SYSERROR("Failed to open gid_map");
+               return 0;
+       }
+
+       while (getline(&line, &sz, f) != -1) {
+               if (sscanf(line, "%u %u %u", &nsid, &hostid, &range) != 3)
+                       continue;
+
+               if (hostid <= orig && hostid + range > orig) {
+                       nsid += orig - hostid;
+                       goto found;
+               }
+       }
+
+       nsid = LXC_INVALID_GID;
+
+found:
+       fclose(f);
+       free(line);
+       return nsid;
+}
 bool dir_exists(const char *path)
 {
        struct stat sb;
index 61e4d99627fc6ab7285eea282d91c405d02ba779..2af0bfd4120fefaa343c2da971a72c605c694f6c 100644 (file)
@@ -415,6 +415,7 @@ inline static bool am_host_unpriv(void)
  * parse /proc/self/uid_map to find what @orig maps to
  */
 extern uid_t get_ns_uid(uid_t orig);
+extern gid_t get_ns_gid(gid_t orig);
 
 extern bool dir_exists(const char *path);