]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
unshare: Add --map-users=all and --map-groups=all
authorChris Webb <chris@arachsys.com>
Thu, 23 Nov 2023 14:06:02 +0000 (14:06 +0000)
committerChris Webb <chris@arachsys.com>
Wed, 29 Nov 2023 21:22:02 +0000 (21:22 +0000)
Accept the special value 'all' for --map-users and --map-groups,
configuring a pass-through mapping of every user or group ID available
in the parent user namespace.

These are invaluable for scripting tests, for example when you want to
remap users leaving groups unchanged, remap groups leaving users unchanged,
or create a pass-through user namespace which maps the same users and
groups as its parent but has no capabilities in that parent namespace.

In the root user namespace, 'all' is equivalent to '0:0:4294967295', but
in child namespaces it may represent a fragmented mapping corresponding
to multiple --map-users or --map-groups options.

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

index 7036612e2dd9358eae761af1183651ff81329f23..e6201e28fffd46052648654f43ffac76a7dd7b06 100644 (file)
@@ -93,16 +93,16 @@ Just before running the program, mount the proc filesystem at _mountpoint_ (defa
 **--map-user=**__uid|name__::
 Run the program only after the current effective user ID has been mapped to _uid_. If this option is specified multiple times, the last occurrence takes precedence. This option implies *--user*.
 
-**--map-users=**__inneruid:outeruid:count__|**auto**::
-Run the program only after the block of user IDs of size _count_ beginning at _outeruid_ has been mapped to the block of user IDs beginning at _inneruid_. This mapping is created with **newuidmap**(1) if *unshare* was run unprivileged. If the range of user IDs overlaps with the mapping specified by *--map-user*, then a "hole" will be removed from the mapping. This may result in the highest user ID of the mapping not being mapped. Use *--map-users* multiple times to map more than one block of user IDs. The special value *auto* will map the first block of user IDs owned by the effective user from _/etc/subuid_ to a block starting at user ID 0. This option implies *--user*.
+**--map-users=**__inneruid:outeruid:count__|**auto**|**all**::
+Run the program only after the block of user IDs of size _count_ beginning at _outeruid_ has been mapped to the block of user IDs beginning at _inneruid_. This mapping is created with **newuidmap**(1) if *unshare* was run unprivileged. If the range of user IDs overlaps with the mapping specified by *--map-user*, then a "hole" will be removed from the mapping. This may result in the highest user ID of the mapping not being mapped. Use *--map-users* multiple times to map more than one block of user IDs. The special value *auto* will map the first block of user IDs owned by the effective user from _/etc/subuid_ to a block starting at user ID 0. The special value *all* will create a pass-through map for every user ID available in the parent namespace. This option implies *--user*.
 +
 Before util-linux version 2.39, this option expected a comma-separated argument of the form _outeruid,inneruid,count_ but that format is now deprecated for consistency with the ordering used in _/proc/[pid]/uid_map_ and the _X-mount.idmap_ mount option.
 
 **--map-group=**__gid|name__::
 Run the program only after the current effective group ID has been mapped to _gid_. If this option is specified multiple times, the last occurrence takes precedence. This option implies *--setgroups=deny* and *--user*.
 
-**--map-groups=**__innergid:outergid:count__|**auto**::
-Run the program only after the block of group IDs of size _count_ beginning at _outergid_ has been mapped to the block of group IDs beginning at _innergid_. This mapping is created with **newgidmap**(1) if *unshare* was run unprivileged. If the range of group IDs overlaps with the mapping specified by *--map-group*, then a "hole" will be removed from the mapping. This may result in the highest group ID of the mapping not being mapped. Use *--map-groups* multiple times to map more than one block of group IDs. The special value *auto* will map the first block of user IDs owned by the effective user from _/etc/subgid_ to a block starting at group ID 0. This option implies *--user*.
+**--map-groups=**__innergid:outergid:count__|**auto**|**all**::
+Run the program only after the block of group IDs of size _count_ beginning at _outergid_ has been mapped to the block of group IDs beginning at _innergid_. This mapping is created with **newgidmap**(1) if *unshare* was run unprivileged. If the range of group IDs overlaps with the mapping specified by *--map-group*, then a "hole" will be removed from the mapping. This may result in the highest group ID of the mapping not being mapped. Use *--map-groups* multiple times to map more than one block of group IDs. The special value *auto* will map the first block of user IDs owned by the effective user from _/etc/subgid_ to a block starting at group ID 0. The special value *all* will create a pass-through map for every group ID available in the parent namespace. This option implies *--user*.
 +
 Before util-linux version 2.39, this option expected a comma-separated argument of the form _outergid,innergid,count_ but that format is now deprecated for consistency with the ordering used in _/proc/[pid]/gid_map_ and the _X-mount.idmap_ mount option.
 
index d1e8db4a7bdd665f1d55a53fcc6e496c61707a51..f92065ac69d9a583e912862874df7b8bbaca22b1 100644 (file)
@@ -479,6 +479,39 @@ static struct map_range read_subid_range(char *filename, uid_t uid)
        pw->pw_name, filename);
 }
 
+/**
+ * read_kernel_map() - Read all available IDs from the kernel
+ * @chain: destination list to receive pass-through ID mappings
+ * @filename: either /proc/self/uid_map or /proc/self/gid_map
+ *
+ * This is used by --map-users=all and --map-groups=all to construct
+ * pass-through mappings for all IDs available in the parent namespace.
+ */
+static void read_kernel_map(struct map_range **chain, char *filename)
+{
+       char *line = NULL;
+       size_t size = 0;
+       FILE *idmap;
+
+       idmap = fopen(filename, "r");
+       if (!idmap)
+               err(EXIT_FAILURE, _("could not open '%s'"), filename);
+
+       while (getline(&line, &size, idmap) != -1) {
+               unsigned int start, count;
+               if (sscanf(line, " %u %*u %u", &start, &count) < 2)
+                       continue;
+               insert_map_range(chain, (struct map_range) {
+                       .inner = start,
+                       .outer = start,
+                       .count = count
+               });
+       }
+
+       fclose(idmap);
+       free(line);
+}
+
 /**
  * add_single_map_range() - Add a single-ID map into a list without overlap
  * @chain: A linked list of ID range mappings
@@ -907,6 +940,8 @@ int main(int argc, char *argv[])
                        if (!strcmp(optarg, "auto"))
                                insert_map_range(&usermap,
                                        read_subid_range(_PATH_SUBUID, real_euid));
+                       else if (!strcmp(optarg, "all"))
+                               read_kernel_map(&usermap, _PATH_PROC_UIDMAP);
                        else
                                insert_map_range(&usermap, get_map_range(optarg));
                        break;
@@ -915,6 +950,8 @@ int main(int argc, char *argv[])
                        if (!strcmp(optarg, "auto"))
                                insert_map_range(&groupmap,
                                        read_subid_range(_PATH_SUBGID, real_euid));
+                       else if (!strcmp(optarg, "all"))
+                               read_kernel_map(&groupmap, _PATH_PROC_GIDMAP);
                        else
                                insert_map_range(&groupmap, get_map_range(optarg));
                        break;