1 // SPDX-License-Identifier: GPL-2.0 2 /* Copyright (c) 2022 Christian Brauner <brauner@kernel.org> */ 3 4 #include <linux/cred.h> 5 #include <linux/fs.h> 6 #include <linux/mnt_idmapping.h> 7 #include <linux/slab.h> 8 #include <linux/user_namespace.h> 9 #include <linux/seq_file.h> 10 11 #include "internal.h" 12 13 /* 14 * Outside of this file vfs{g,u}id_t are always created from k{g,u}id_t, 15 * never from raw values. These are just internal helpers. 16 */ 17 #define VFSUIDT_INIT_RAW(val) (vfsuid_t){ val } 18 #define VFSGIDT_INIT_RAW(val) (vfsgid_t){ val } 19 20 struct mnt_idmap { 21 struct uid_gid_map uid_map; 22 struct uid_gid_map gid_map; 23 refcount_t count; 24 }; 25 26 /* 27 * Carries the initial idmapping of 0:0:4294967295 which is an identity 28 * mapping. This means that {g,u}id 0 is mapped to {g,u}id 0, {g,u}id 1 is 29 * mapped to {g,u}id 1, [...], {g,u}id 1000 to {g,u}id 1000, [...]. 30 */ 31 struct mnt_idmap nop_mnt_idmap = { 32 .count = REFCOUNT_INIT(1), 33 }; 34 EXPORT_SYMBOL_GPL(nop_mnt_idmap); 35 36 /* 37 * Carries the invalid idmapping of a full 0-4294967295 {g,u}id range. 38 * This means that all {g,u}ids are mapped to INVALID_VFS{G,U}ID. 39 */ 40 struct mnt_idmap invalid_mnt_idmap = { 41 .count = REFCOUNT_INIT(1), 42 }; 43 EXPORT_SYMBOL_GPL(invalid_mnt_idmap); 44 45 /** 46 * initial_idmapping - check whether this is the initial mapping 47 * @ns: idmapping to check 48 * 49 * Check whether this is the initial mapping, mapping 0 to 0, 1 to 1, 50 * [...], 1000 to 1000 [...]. 51 * 52 * Return: true if this is the initial mapping, false if not. 53 */ 54 static inline bool initial_idmapping(const struct user_namespace *ns) 55 { 56 return ns == &init_user_ns; 57 } 58 59 /** 60 * make_vfsuid - map a filesystem kuid according to an idmapping 61 * @idmap: the mount's idmapping 62 * @fs_userns: the filesystem's idmapping 63 * @kuid : kuid to be mapped 64 * 65 * Take a @kuid and remap it from @fs_userns into @idmap. Use this 66 * function when preparing a @kuid to be reported to userspace. 67 * 68 * If initial_idmapping() determines that this is not an idmapped mount 69 * we can simply return @kuid unchanged. 70 * If initial_idmapping() tells us that the filesystem is not mounted with an 71 * idmapping we know the value of @kuid won't change when calling 72 * from_kuid() so we can simply retrieve the value via __kuid_val() 73 * directly. 74 * 75 * Return: @kuid mapped according to @idmap. 76 * If @kuid has no mapping in either @idmap or @fs_userns INVALID_UID is 77 * returned. 78 */ 79 80 vfsuid_t make_vfsuid(struct mnt_idmap *idmap, 81 struct user_namespace *fs_userns, 82 kuid_t kuid) 83 { 84 uid_t uid; 85 86 if (idmap == &nop_mnt_idmap) 87 return VFSUIDT_INIT(kuid); 88 if (idmap == &invalid_mnt_idmap) 89 return INVALID_VFSUID; 90 if (initial_idmapping(fs_userns)) 91 uid = __kuid_val(kuid); 92 else 93 uid = from_kuid(fs_userns, kuid); 94 if (uid == (uid_t)-1) 95 return INVALID_VFSUID; 96 return VFSUIDT_INIT_RAW(map_id_down(&idmap->uid_map, uid)); 97 } 98 EXPORT_SYMBOL_GPL(make_vfsuid); 99 100 /** 101 * make_vfsgid - map a filesystem kgid according to an idmapping 102 * @idmap: the mount's idmapping 103 * @fs_userns: the filesystem's idmapping 104 * @kgid : kgid to be mapped 105 * 106 * Take a @kgid and remap it from @fs_userns into @idmap. Use this 107 * function when preparing a @kgid to be reported to userspace. 108 * 109 * If initial_idmapping() determines that this is not an idmapped mount 110 * we can simply return @kgid unchanged. 111 * If initial_idmapping() tells us that the filesystem is not mounted with an 112 * idmapping we know the value of @kgid won't change when calling 113 * from_kgid() so we can simply retrieve the value via __kgid_val() 114 * directly. 115 * 116 * Return: @kgid mapped according to @idmap. 117 * If @kgid has no mapping in either @idmap or @fs_userns INVALID_GID is 118 * returned. 119 */ 120 vfsgid_t make_vfsgid(struct mnt_idmap *idmap, 121 struct user_namespace *fs_userns, kgid_t kgid) 122 { 123 gid_t gid; 124 125 if (idmap == &nop_mnt_idmap) 126 return VFSGIDT_INIT(kgid); 127 if (idmap == &invalid_mnt_idmap) 128 return INVALID_VFSGID; 129 if (initial_idmapping(fs_userns)) 130 gid = __kgid_val(kgid); 131 else 132 gid = from_kgid(fs_userns, kgid); 133 if (gid == (gid_t)-1) 134 return INVALID_VFSGID; 135 return VFSGIDT_INIT_RAW(map_id_down(&idmap->gid_map, gid)); 136 } 137 EXPORT_SYMBOL_GPL(make_vfsgid); 138 139 /** 140 * from_vfsuid - map a vfsuid into the filesystem idmapping 141 * @idmap: the mount's idmapping 142 * @fs_userns: the filesystem's idmapping 143 * @vfsuid : vfsuid to be mapped 144 * 145 * Map @vfsuid into the filesystem idmapping. This function has to be used in 146 * order to e.g. write @vfsuid to inode->i_uid. 147 * 148 * Return: @vfsuid mapped into the filesystem idmapping 149 */ 150 kuid_t from_vfsuid(struct mnt_idmap *idmap, 151 struct user_namespace *fs_userns, vfsuid_t vfsuid) 152 { 153 uid_t uid; 154 155 if (idmap == &nop_mnt_idmap) 156 return AS_KUIDT(vfsuid); 157 if (idmap == &invalid_mnt_idmap) 158 return INVALID_UID; 159 uid = map_id_up(&idmap->uid_map, __vfsuid_val(vfsuid)); 160 if (uid == (uid_t)-1) 161 return INVALID_UID; 162 if (initial_idmapping(fs_userns)) 163 return KUIDT_INIT(uid); 164 return make_kuid(fs_userns, uid); 165 } 166 EXPORT_SYMBOL_GPL(from_vfsuid); 167 168 /** 169 * from_vfsgid - map a vfsgid into the filesystem idmapping 170 * @idmap: the mount's idmapping 171 * @fs_userns: the filesystem's idmapping 172 * @vfsgid : vfsgid to be mapped 173 * 174 * Map @vfsgid into the filesystem idmapping. This function has to be used in 175 * order to e.g. write @vfsgid to inode->i_gid. 176 * 177 * Return: @vfsgid mapped into the filesystem idmapping 178 */ 179 kgid_t from_vfsgid(struct mnt_idmap *idmap, 180 struct user_namespace *fs_userns, vfsgid_t vfsgid) 181 { 182 gid_t gid; 183 184 if (idmap == &nop_mnt_idmap) 185 return AS_KGIDT(vfsgid); 186 if (idmap == &invalid_mnt_idmap) 187 return INVALID_GID; 188 gid = map_id_up(&idmap->gid_map, __vfsgid_val(vfsgid)); 189 if (gid == (gid_t)-1) 190 return INVALID_GID; 191 if (initial_idmapping(fs_userns)) 192 return KGIDT_INIT(gid); 193 return make_kgid(fs_userns, gid); 194 } 195 EXPORT_SYMBOL_GPL(from_vfsgid); 196 197 #ifdef CONFIG_MULTIUSER 198 /** 199 * vfsgid_in_group_p() - check whether a vfsuid matches the caller's groups 200 * @vfsgid: the mnt gid to match 201 * 202 * This function can be used to determine whether @vfsuid matches any of the 203 * caller's groups. 204 * 205 * Return: 1 if vfsuid matches caller's groups, 0 if not. 206 */ 207 int vfsgid_in_group_p(vfsgid_t vfsgid) 208 { 209 return in_group_p(AS_KGIDT(vfsgid)); 210 } 211 #else 212 int vfsgid_in_group_p(vfsgid_t vfsgid) 213 { 214 return 1; 215 } 216 #endif 217 EXPORT_SYMBOL_GPL(vfsgid_in_group_p); 218 219 static int copy_mnt_idmap(struct uid_gid_map *map_from, 220 struct uid_gid_map *map_to) 221 { 222 struct uid_gid_extent *forward, *reverse; 223 u32 nr_extents = READ_ONCE(map_from->nr_extents); 224 /* Pairs with smp_wmb() when writing the idmapping. */ 225 smp_rmb(); 226 227 /* 228 * Don't blindly copy @map_to into @map_from if nr_extents is 229 * smaller or equal to UID_GID_MAP_MAX_BASE_EXTENTS. Since we 230 * read @nr_extents someone could have written an idmapping and 231 * then we might end up with inconsistent data. So just don't do 232 * anything at all. 233 */ 234 if (nr_extents == 0) 235 return -EINVAL; 236 237 /* 238 * Here we know that nr_extents is greater than zero which means 239 * a map has been written. Since idmappings can't be changed 240 * once they have been written we know that we can safely copy 241 * from @map_to into @map_from. 242 */ 243 244 if (nr_extents <= UID_GID_MAP_MAX_BASE_EXTENTS) { 245 *map_to = *map_from; 246 return 0; 247 } 248 249 forward = kmemdup_array(map_from->forward, nr_extents, 250 sizeof(struct uid_gid_extent), 251 GFP_KERNEL_ACCOUNT); 252 if (!forward) 253 return -ENOMEM; 254 255 reverse = kmemdup_array(map_from->reverse, nr_extents, 256 sizeof(struct uid_gid_extent), 257 GFP_KERNEL_ACCOUNT); 258 if (!reverse) { 259 kfree(forward); 260 return -ENOMEM; 261 } 262 263 /* 264 * The idmapping isn't exposed anywhere so we don't need to care 265 * about ordering between extent pointers and @nr_extents 266 * initialization. 267 */ 268 map_to->forward = forward; 269 map_to->reverse = reverse; 270 map_to->nr_extents = nr_extents; 271 return 0; 272 } 273 274 static void free_mnt_idmap(struct mnt_idmap *idmap) 275 { 276 if (idmap->uid_map.nr_extents > UID_GID_MAP_MAX_BASE_EXTENTS) { 277 kfree(idmap->uid_map.forward); 278 kfree(idmap->uid_map.reverse); 279 } 280 if (idmap->gid_map.nr_extents > UID_GID_MAP_MAX_BASE_EXTENTS) { 281 kfree(idmap->gid_map.forward); 282 kfree(idmap->gid_map.reverse); 283 } 284 kfree(idmap); 285 } 286 287 struct mnt_idmap *alloc_mnt_idmap(struct user_namespace *mnt_userns) 288 { 289 struct mnt_idmap *idmap; 290 int ret; 291 292 idmap = kzalloc(sizeof(struct mnt_idmap), GFP_KERNEL_ACCOUNT); 293 if (!idmap) 294 return ERR_PTR(-ENOMEM); 295 296 refcount_set(&idmap->count, 1); 297 ret = copy_mnt_idmap(&mnt_userns->uid_map, &idmap->uid_map); 298 if (!ret) 299 ret = copy_mnt_idmap(&mnt_userns->gid_map, &idmap->gid_map); 300 if (ret) { 301 free_mnt_idmap(idmap); 302 idmap = ERR_PTR(ret); 303 } 304 return idmap; 305 } 306 307 /** 308 * mnt_idmap_get - get a reference to an idmapping 309 * @idmap: the idmap to bump the reference on 310 * 311 * If @idmap is not the @nop_mnt_idmap bump the reference count. 312 * 313 * Return: @idmap with reference count bumped if @not_mnt_idmap isn't passed. 314 */ 315 struct mnt_idmap *mnt_idmap_get(struct mnt_idmap *idmap) 316 { 317 if (idmap != &nop_mnt_idmap && idmap != &invalid_mnt_idmap) 318 refcount_inc(&idmap->count); 319 320 return idmap; 321 } 322 EXPORT_SYMBOL_GPL(mnt_idmap_get); 323 324 /** 325 * mnt_idmap_put - put a reference to an idmapping 326 * @idmap: the idmap to put the reference on 327 * 328 * If this is a non-initial idmapping, put the reference count when a mount is 329 * released and free it if we're the last user. 330 */ 331 void mnt_idmap_put(struct mnt_idmap *idmap) 332 { 333 if (idmap != &nop_mnt_idmap && idmap != &invalid_mnt_idmap && 334 refcount_dec_and_test(&idmap->count)) 335 free_mnt_idmap(idmap); 336 } 337 EXPORT_SYMBOL_GPL(mnt_idmap_put); 338 339 int statmount_mnt_idmap(struct mnt_idmap *idmap, struct seq_file *seq, bool uid_map) 340 { 341 struct uid_gid_map *map, *map_up; 342 u32 idx, nr_mappings; 343 344 if (!is_valid_mnt_idmap(idmap)) 345 return 0; 346 347 /* 348 * Idmappings are shown relative to the caller's idmapping. 349 * This is both the most intuitive and most useful solution. 350 */ 351 if (uid_map) { 352 map = &idmap->uid_map; 353 map_up = ¤t_user_ns()->uid_map; 354 } else { 355 map = &idmap->gid_map; 356 map_up = ¤t_user_ns()->gid_map; 357 } 358 359 for (idx = 0, nr_mappings = 0; idx < map->nr_extents; idx++) { 360 uid_t lower; 361 struct uid_gid_extent *extent; 362 363 if (map->nr_extents <= UID_GID_MAP_MAX_BASE_EXTENTS) 364 extent = &map->extent[idx]; 365 else 366 extent = &map->forward[idx]; 367 368 /* 369 * Verify that the whole range of the mapping can be 370 * resolved in the caller's idmapping. If it cannot be 371 * resolved skip the mapping. 372 */ 373 lower = map_id_range_up(map_up, extent->lower_first, extent->count); 374 if (lower == (uid_t) -1) 375 continue; 376 377 seq_printf(seq, "%u %u %u", extent->first, lower, extent->count); 378 379 seq->count++; /* mappings are separated by \0 */ 380 if (seq_has_overflowed(seq)) 381 return -EAGAIN; 382 383 nr_mappings++; 384 } 385 386 return nr_mappings; 387 } 388