On Tue, 2025-02-04 at 12:27 +0100, Christian Brauner wrote: > This adds the STATMOUNT_MNT_UIDMAP and STATMOUNT_MNT_GIDMAP options. > It allows the retrieval of idmappings via statmount(). > > Currently it isn't possible to figure out what idmappings are applied to > an idmapped mount. This information is often crucial. Before statmount() > the only realistic options for an interface like this would have been to > add it to /proc/<pid>/fdinfo/<nr> or to expose it in > /proc/<pid>/mountinfo. Both solution would have been pretty ugly and > would've shown information that is of strong interest to some > application but not all. statmount() is perfect for this. > > The idmappings applied to an idmapped mount are shown relative to the > caller's user namespace. This is the most useful solution that doesn't > risk leaking information or confuse the caller. > > For example, an idmapped mount might have been created with the > following idmappings: > > mount --bind -o X-mount.idmap="0:10000:1000 2000:2000:1 3000:3000:1" /srv /opt > > Listing the idmappings through statmount() in the same context shows: > > mnt_id: 2147485088 > mnt_parent_id: 2147484816 > fs_type: btrfs > mnt_root: /srv > mnt_point: /opt > mnt_opts: ssd,discard=async,space_cache=v2,subvolid=5,subvol=/ > mnt_uidmap[0]: 0 10000 1000 > mnt_uidmap[1]: 2000 2000 1 > mnt_uidmap[2]: 3000 3000 1 > mnt_gidmap[0]: 0 10000 1000 > mnt_gidmap[1]: 2000 2000 1 > mnt_gidmap[2]: 3000 3000 1 > > But the idmappings might not always be resolvable in the caller's user > namespace. For example: > > unshare --user --map-root > > In this case statmount() will skip any mappings that fil to resolve in > the caller's idmapping: > > mnt_id: 2147485087 > mnt_parent_id: 2147484016 > fs_type: btrfs > mnt_root: /srv > mnt_point: /opt > mnt_opts: ssd,discard=async,space_cache=v2,subvolid=5,subvol=/ > > The caller can differentiate between a mount not being idmapped and a > mount that is idmapped but where all mappings fail to resolve in the > caller's idmapping by check for the STATMOUNT_MNT_{G,U}IDMAP flag being > raised but the number of mappings in ->mnt_{g,u}idmap_num being zero. > > Note that statmount() requires that the whole range must be resolvable > in the caller's user namespace. If a subrange fails to map it will still > list the map as not resolvable. This is a practical compromise to avoid > having to find which subranges are resovable and wich aren't. > > Idmappings are listed as a string array with each mapping separated by > zero bytes. This allows to retrieve the idmappings and immediately use > them for writing to e.g., /proc/<pid>/{g,u}id_map and it also allow for > simple iteration like: > > if (stmnt->mask & STATMOUNT_MNT_UIDMAP) { > const char *idmap = stmnt->str + stmnt->mnt_uidmap; > > for (size_t idx = 0; idx < stmnt->mnt_uidmap_nr; idx++) { > printf("mnt_uidmap[%lu]: %s\n", idx, idmap); > idmap += strlen(idmap) + 1; > } > } > > Signed-off-by: Christian Brauner <brauner@xxxxxxxxxx> > --- > Changes in v2: > - EDITME: describe what is new in this series revision. > - EDITME: use bulletpoints and terse descriptions. > - Link to v1: https://lore.kernel.org/r/20250130-work-mnt_idmap-statmount-v1-0-d4ced5874e14@xxxxxxxxxx > > --- > Christian Brauner (4): > uidgid: add map_id_range_up() > statmount: allow to retrieve idmappings > samples/vfs: check whether flag was raised > samples/vfs: add STATMOUNT_MNT_{G,U}IDMAP > > fs/internal.h | 1 + > fs/mnt_idmapping.c | 51 ++++++++++++++++++++++++++++++++ > fs/namespace.c | 59 +++++++++++++++++++++++++++++++++++++- > include/linux/mnt_idmapping.h | 5 ++++ > include/linux/uidgid.h | 6 ++++ > include/uapi/linux/mount.h | 8 +++++- > kernel/user_namespace.c | 26 +++++++++++------ > samples/vfs/samples-vfs.h | 14 ++++++++- > samples/vfs/test-list-all-mounts.c | 35 ++++++++++++++++++---- > 9 files changed, 187 insertions(+), 18 deletions(-) > --- > base-commit: 2014c95afecee3e76ca4a56956a936e23283f05b > change-id: 20250129-work-mnt_idmap-statmount-e57f258fef8e > This all looks pretty sane to me. Reviewed-by: Jeff Layton <jlayton@xxxxxxxxxx>