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 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*.
+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*.
+
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.
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 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*.
+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*.
+
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.
}
/**
- * map_ids() - Create a new uid/gid map
+ * map_ids_external() - Create a new uid/gid map using setuid helper
* @idmapper: Either newuidmap or newgidmap
* @ppid: Pid to set the map for
* @chain: A linked list of ID range mappings
* This function always exec()s or errors out and does not return.
*/
static void __attribute__((__noreturn__))
-map_ids(const char *idmapper, int ppid, struct map_range *chain)
+map_ids_external(const char *idmapper, int ppid, struct map_range *chain)
{
unsigned int i = 0, length = 3;
char **argv;
errexec(idmapper);
}
+/**
+ * map_ids_internal() - Create a new uid/gid map using root privilege
+ * @type: Either uid_map or gid_map
+ * @ppid: Pid to set the map for
+ * @chain: A linked list of ID range mappings
+ *
+ * This creates a new uid/gid map for @ppid using a privileged write to
+ * /proc/@ppid/@type to set a mapping for each of the ranges in @chain.
+ */
+static void map_ids_internal(const char *type, int ppid, struct map_range *chain)
+{
+ int count, fd;
+ unsigned int length = 0;
+ char buffer[4096], *path;
+
+ xasprintf(&path, "/proc/%u/%s", ppid, type);
+ for (struct map_range *map = chain; map; map = map->next) {
+ count = snprintf(buffer + length, sizeof(buffer) - length,
+ "%u %u %u\n",
+ map->inner, map->outer, map->count);
+ if (count < 0 || count + length > sizeof(buffer))
+ errx(EXIT_FAILURE,
+ _("%s too large for kernel 4k limit"), path);
+ length += count;
+ }
+
+ fd = open(path, O_WRONLY | O_CLOEXEC | O_NOCTTY);
+ if (fd < 0)
+ err(EXIT_FAILURE, _("failed to open %s"), path);
+ if (write_all(fd, buffer, length) < 0)
+ err(EXIT_FAILURE, _("failed to write %s"), path);
+ close(fd);
+ free(path);
+}
+
/**
* map_ids_from_child() - Set up a new uid/gid map
* @fd: The eventfd to wait on
if (groupmap)
add_single_map_range(&groupmap, getegid(), mapgroup);
+ if (geteuid() == 0) {
+ if (usermap)
+ map_ids_internal("uid_map", ppid, usermap);
+ if (groupmap)
+ map_ids_internal("gid_map", ppid, groupmap);
+ exit(EXIT_SUCCESS);
+ }
+
/* Avoid forking more than we need to */
if (usermap && groupmap) {
pid = fork();
}
if (!pid && usermap)
- map_ids("newuidmap", ppid, usermap);
+ map_ids_external("newuidmap", ppid, usermap);
if (groupmap)
- map_ids("newgidmap", ppid, groupmap);
+ map_ids_external("newgidmap", ppid, groupmap);
exit(EXIT_SUCCESS);
}