]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
unshare: Don't waste an ID when -r is used with --map-auto
authorChris Webb <chris@arachsys.com>
Wed, 24 Aug 2022 11:52:55 +0000 (12:52 +0100)
committerKarel Zak <kzak@redhat.com>
Thu, 1 Sep 2022 09:30:03 +0000 (11:30 +0200)
When --map-root-user or --map-current-user are used with --map-auto, one of
the IDs from the first range in /etc/subuid and /etc/subgid is wasted and
left unmapped:

  $ cat /etc/subuid
  1000:65536:100
  $ unshare --map-auto cat /proc/self/uid_map
           0      65536        100
  $ unshare --map-root-user --map-auto cat /proc/self/uid_map
           0       1000          1
           1      65536         99

In the second unshare, only 99 of the 100 UIDs available from /etc/subuid
are actually mapped, whereas in the first unshare, all 100 delegated UIDs
are correctly mapped.

Distinguish auto mappings from manually-specified ones so they can be
handled correctly, while still ensuring explicit --map-users/groups that
overlap with the single mapping are correctly reduced in length because
of the hole that's punched:

  $ unshare --map-auto cat /proc/self/uid_map
           0      65536        100
  $ unshare  --map-root-user --map-auto cat /proc/self/uid_map
           0       1000          1
           1      65536        100

Signed-off-by: Chris Webb <chris@arachsys.com>
sys-utils/unshare.c

index a379e8aedec7a4bdc16b046f685b6d3133a5930d..f5fe046a89a69ca7f1ba67a9f4e05238d752e8b9 100644 (file)
@@ -437,7 +437,7 @@ static struct map_range *read_subid_range(char *filename, uid_t uid)
        struct map_range *map;
 
        map = xmalloc(sizeof(*map));
-       map->inner = 0;
+       map->inner = -1;
 
        pw = xgetpwuid(uid, &pwbuf);
        if (!pw)
@@ -538,10 +538,10 @@ map_ids(const char *idmapper, int ppid, unsigned int outer, unsigned int inner,
        push_ul(ppid);
        if ((int)inner == -1) {
                /*
-                * If we don't have a "single" mapping, then we can just use
-                * map directly
+                * If we don't have a "single" mapping, then we can just use map
+                * directly, starting inner IDs from zero for an auto mapping
                 */
-               push_ul(map->inner);
+               push_ul(map->inner + 1 ? map->inner : 0);
                push_ul(map->outer);
                push_ul(map->count);
                push_str(NULL);
@@ -550,9 +550,14 @@ map_ids(const char *idmapper, int ppid, unsigned int outer, unsigned int inner,
                errexec(idmapper);
        }
 
-       /* If the mappings overlap, remove an ID from map */
-       if ((outer >= map->outer && outer <= map->outer + map->count) ||
-           (inner >= map->inner && inner <= map->inner + map->count))
+       /*
+        * Start inner IDs from zero for an auto mapping; otherwise, if the two
+        * fixed mappings overlap, remove an ID from map
+        */
+       if (map->inner + 1 == 0)
+               map->inner = 0;
+       else if ((outer >= map->outer && outer <= map->outer + map->count) ||
+                (inner >= map->inner && inner <= map->inner + map->count))
                map->count--;
 
        /* Determine where the splits between lo, mid, and hi will be */