at v6.0 14 kB view raw
1/* SPDX-License-Identifier: GPL-2.0 */ 2#ifndef _LINUX_MNT_IDMAPPING_H 3#define _LINUX_MNT_IDMAPPING_H 4 5#include <linux/types.h> 6#include <linux/uidgid.h> 7 8struct user_namespace; 9/* 10 * Carries the initial idmapping of 0:0:4294967295 which is an identity 11 * mapping. This means that {g,u}id 0 is mapped to {g,u}id 0, {g,u}id 1 is 12 * mapped to {g,u}id 1, [...], {g,u}id 1000 to {g,u}id 1000, [...]. 13 */ 14extern struct user_namespace init_user_ns; 15 16typedef struct { 17 uid_t val; 18} vfsuid_t; 19 20typedef struct { 21 gid_t val; 22} vfsgid_t; 23 24static_assert(sizeof(vfsuid_t) == sizeof(kuid_t)); 25static_assert(sizeof(vfsgid_t) == sizeof(kgid_t)); 26static_assert(offsetof(vfsuid_t, val) == offsetof(kuid_t, val)); 27static_assert(offsetof(vfsgid_t, val) == offsetof(kgid_t, val)); 28 29#ifdef CONFIG_MULTIUSER 30static inline uid_t __vfsuid_val(vfsuid_t uid) 31{ 32 return uid.val; 33} 34 35static inline gid_t __vfsgid_val(vfsgid_t gid) 36{ 37 return gid.val; 38} 39#else 40static inline uid_t __vfsuid_val(vfsuid_t uid) 41{ 42 return 0; 43} 44 45static inline gid_t __vfsgid_val(vfsgid_t gid) 46{ 47 return 0; 48} 49#endif 50 51static inline bool vfsuid_valid(vfsuid_t uid) 52{ 53 return __vfsuid_val(uid) != (uid_t)-1; 54} 55 56static inline bool vfsgid_valid(vfsgid_t gid) 57{ 58 return __vfsgid_val(gid) != (gid_t)-1; 59} 60 61static inline bool vfsuid_eq(vfsuid_t left, vfsuid_t right) 62{ 63 return vfsuid_valid(left) && __vfsuid_val(left) == __vfsuid_val(right); 64} 65 66static inline bool vfsgid_eq(vfsgid_t left, vfsgid_t right) 67{ 68 return vfsgid_valid(left) && __vfsgid_val(left) == __vfsgid_val(right); 69} 70 71/** 72 * vfsuid_eq_kuid - check whether kuid and vfsuid have the same value 73 * @vfsuid: the vfsuid to compare 74 * @kuid: the kuid to compare 75 * 76 * Check whether @vfsuid and @kuid have the same values. 77 * 78 * Return: true if @vfsuid and @kuid have the same value, false if not. 79 * Comparison between two invalid uids returns false. 80 */ 81static inline bool vfsuid_eq_kuid(vfsuid_t vfsuid, kuid_t kuid) 82{ 83 return vfsuid_valid(vfsuid) && __vfsuid_val(vfsuid) == __kuid_val(kuid); 84} 85 86/** 87 * vfsgid_eq_kgid - check whether kgid and vfsgid have the same value 88 * @vfsgid: the vfsgid to compare 89 * @kgid: the kgid to compare 90 * 91 * Check whether @vfsgid and @kgid have the same values. 92 * 93 * Return: true if @vfsgid and @kgid have the same value, false if not. 94 * Comparison between two invalid gids returns false. 95 */ 96static inline bool vfsgid_eq_kgid(vfsgid_t vfsgid, kgid_t kgid) 97{ 98 return vfsgid_valid(vfsgid) && __vfsgid_val(vfsgid) == __kgid_val(kgid); 99} 100 101/* 102 * vfs{g,u}ids are created from k{g,u}ids. 103 * We don't allow them to be created from regular {u,g}id. 104 */ 105#define VFSUIDT_INIT(val) (vfsuid_t){ __kuid_val(val) } 106#define VFSGIDT_INIT(val) (vfsgid_t){ __kgid_val(val) } 107 108#define INVALID_VFSUID VFSUIDT_INIT(INVALID_UID) 109#define INVALID_VFSGID VFSGIDT_INIT(INVALID_GID) 110 111/* 112 * Allow a vfs{g,u}id to be used as a k{g,u}id where we want to compare 113 * whether the mapped value is identical to value of a k{g,u}id. 114 */ 115#define AS_KUIDT(val) (kuid_t){ __vfsuid_val(val) } 116#define AS_KGIDT(val) (kgid_t){ __vfsgid_val(val) } 117 118#ifdef CONFIG_MULTIUSER 119/** 120 * vfsgid_in_group_p() - check whether a vfsuid matches the caller's groups 121 * @vfsgid: the mnt gid to match 122 * 123 * This function can be used to determine whether @vfsuid matches any of the 124 * caller's groups. 125 * 126 * Return: 1 if vfsuid matches caller's groups, 0 if not. 127 */ 128static inline int vfsgid_in_group_p(vfsgid_t vfsgid) 129{ 130 return in_group_p(AS_KGIDT(vfsgid)); 131} 132#else 133static inline int vfsgid_in_group_p(vfsgid_t vfsgid) 134{ 135 return 1; 136} 137#endif 138 139/** 140 * initial_idmapping - check whether this is the initial mapping 141 * @ns: idmapping to check 142 * 143 * Check whether this is the initial mapping, mapping 0 to 0, 1 to 1, 144 * [...], 1000 to 1000 [...]. 145 * 146 * Return: true if this is the initial mapping, false if not. 147 */ 148static inline bool initial_idmapping(const struct user_namespace *ns) 149{ 150 return ns == &init_user_ns; 151} 152 153/** 154 * no_idmapping - check whether we can skip remapping a kuid/gid 155 * @mnt_userns: the mount's idmapping 156 * @fs_userns: the filesystem's idmapping 157 * 158 * This function can be used to check whether a remapping between two 159 * idmappings is required. 160 * An idmapped mount is a mount that has an idmapping attached to it that 161 * is different from the filsystem's idmapping and the initial idmapping. 162 * If the initial mapping is used or the idmapping of the mount and the 163 * filesystem are identical no remapping is required. 164 * 165 * Return: true if remapping can be skipped, false if not. 166 */ 167static inline bool no_idmapping(const struct user_namespace *mnt_userns, 168 const struct user_namespace *fs_userns) 169{ 170 return initial_idmapping(mnt_userns) || mnt_userns == fs_userns; 171} 172 173/** 174 * make_vfsuid - map a filesystem kuid into a mnt_userns 175 * @mnt_userns: the mount's idmapping 176 * @fs_userns: the filesystem's idmapping 177 * @kuid : kuid to be mapped 178 * 179 * Take a @kuid and remap it from @fs_userns into @mnt_userns. Use this 180 * function when preparing a @kuid to be reported to userspace. 181 * 182 * If no_idmapping() determines that this is not an idmapped mount we can 183 * simply return @kuid unchanged. 184 * If initial_idmapping() tells us that the filesystem is not mounted with an 185 * idmapping we know the value of @kuid won't change when calling 186 * from_kuid() so we can simply retrieve the value via __kuid_val() 187 * directly. 188 * 189 * Return: @kuid mapped according to @mnt_userns. 190 * If @kuid has no mapping in either @mnt_userns or @fs_userns INVALID_UID is 191 * returned. 192 */ 193 194static inline vfsuid_t make_vfsuid(struct user_namespace *mnt_userns, 195 struct user_namespace *fs_userns, 196 kuid_t kuid) 197{ 198 uid_t uid; 199 200 if (no_idmapping(mnt_userns, fs_userns)) 201 return VFSUIDT_INIT(kuid); 202 if (initial_idmapping(fs_userns)) 203 uid = __kuid_val(kuid); 204 else 205 uid = from_kuid(fs_userns, kuid); 206 if (uid == (uid_t)-1) 207 return INVALID_VFSUID; 208 return VFSUIDT_INIT(make_kuid(mnt_userns, uid)); 209} 210 211static inline kuid_t mapped_kuid_fs(struct user_namespace *mnt_userns, 212 struct user_namespace *fs_userns, 213 kuid_t kuid) 214{ 215 return AS_KUIDT(make_vfsuid(mnt_userns, fs_userns, kuid)); 216} 217 218/** 219 * make_vfsgid - map a filesystem kgid into a mnt_userns 220 * @mnt_userns: the mount's idmapping 221 * @fs_userns: the filesystem's idmapping 222 * @kgid : kgid to be mapped 223 * 224 * Take a @kgid and remap it from @fs_userns into @mnt_userns. Use this 225 * function when preparing a @kgid to be reported to userspace. 226 * 227 * If no_idmapping() determines that this is not an idmapped mount we can 228 * simply return @kgid unchanged. 229 * If initial_idmapping() tells us that the filesystem is not mounted with an 230 * idmapping we know the value of @kgid won't change when calling 231 * from_kgid() so we can simply retrieve the value via __kgid_val() 232 * directly. 233 * 234 * Return: @kgid mapped according to @mnt_userns. 235 * If @kgid has no mapping in either @mnt_userns or @fs_userns INVALID_GID is 236 * returned. 237 */ 238 239static inline vfsgid_t make_vfsgid(struct user_namespace *mnt_userns, 240 struct user_namespace *fs_userns, 241 kgid_t kgid) 242{ 243 gid_t gid; 244 245 if (no_idmapping(mnt_userns, fs_userns)) 246 return VFSGIDT_INIT(kgid); 247 if (initial_idmapping(fs_userns)) 248 gid = __kgid_val(kgid); 249 else 250 gid = from_kgid(fs_userns, kgid); 251 if (gid == (gid_t)-1) 252 return INVALID_VFSGID; 253 return VFSGIDT_INIT(make_kgid(mnt_userns, gid)); 254} 255 256static inline kgid_t mapped_kgid_fs(struct user_namespace *mnt_userns, 257 struct user_namespace *fs_userns, 258 kgid_t kgid) 259{ 260 return AS_KGIDT(make_vfsgid(mnt_userns, fs_userns, kgid)); 261} 262 263/** 264 * from_vfsuid - map a vfsuid into the filesystem idmapping 265 * @mnt_userns: the mount's idmapping 266 * @fs_userns: the filesystem's idmapping 267 * @vfsuid : vfsuid to be mapped 268 * 269 * Map @vfsuid into the filesystem idmapping. This function has to be used in 270 * order to e.g. write @vfsuid to inode->i_uid. 271 * 272 * Return: @vfsuid mapped into the filesystem idmapping 273 */ 274static inline kuid_t from_vfsuid(struct user_namespace *mnt_userns, 275 struct user_namespace *fs_userns, 276 vfsuid_t vfsuid) 277{ 278 uid_t uid; 279 280 if (no_idmapping(mnt_userns, fs_userns)) 281 return AS_KUIDT(vfsuid); 282 uid = from_kuid(mnt_userns, AS_KUIDT(vfsuid)); 283 if (uid == (uid_t)-1) 284 return INVALID_UID; 285 if (initial_idmapping(fs_userns)) 286 return KUIDT_INIT(uid); 287 return make_kuid(fs_userns, uid); 288} 289 290/** 291 * mapped_kuid_user - map a user kuid into a mnt_userns 292 * @mnt_userns: the mount's idmapping 293 * @fs_userns: the filesystem's idmapping 294 * @kuid : kuid to be mapped 295 * 296 * Use the idmapping of @mnt_userns to remap a @kuid into @fs_userns. Use this 297 * function when preparing a @kuid to be written to disk or inode. 298 * 299 * If no_idmapping() determines that this is not an idmapped mount we can 300 * simply return @kuid unchanged. 301 * If initial_idmapping() tells us that the filesystem is not mounted with an 302 * idmapping we know the value of @kuid won't change when calling 303 * make_kuid() so we can simply retrieve the value via KUIDT_INIT() 304 * directly. 305 * 306 * Return: @kuid mapped according to @mnt_userns. 307 * If @kuid has no mapping in either @mnt_userns or @fs_userns INVALID_UID is 308 * returned. 309 */ 310static inline kuid_t mapped_kuid_user(struct user_namespace *mnt_userns, 311 struct user_namespace *fs_userns, 312 kuid_t kuid) 313{ 314 return from_vfsuid(mnt_userns, fs_userns, VFSUIDT_INIT(kuid)); 315} 316 317/** 318 * vfsuid_has_fsmapping - check whether a vfsuid maps into the filesystem 319 * @mnt_userns: the mount's idmapping 320 * @fs_userns: the filesystem's idmapping 321 * @vfsuid: vfsuid to be mapped 322 * 323 * Check whether @vfsuid has a mapping in the filesystem idmapping. Use this 324 * function to check whether the filesystem idmapping has a mapping for 325 * @vfsuid. 326 * 327 * Return: true if @vfsuid has a mapping in the filesystem, false if not. 328 */ 329static inline bool vfsuid_has_fsmapping(struct user_namespace *mnt_userns, 330 struct user_namespace *fs_userns, 331 vfsuid_t vfsuid) 332{ 333 return uid_valid(from_vfsuid(mnt_userns, fs_userns, vfsuid)); 334} 335 336/** 337 * vfsuid_into_kuid - convert vfsuid into kuid 338 * @vfsuid: the vfsuid to convert 339 * 340 * This can be used when a vfsuid is committed as a kuid. 341 * 342 * Return: a kuid with the value of @vfsuid 343 */ 344static inline kuid_t vfsuid_into_kuid(vfsuid_t vfsuid) 345{ 346 return AS_KUIDT(vfsuid); 347} 348 349/** 350 * from_vfsgid - map a vfsgid into the filesystem idmapping 351 * @mnt_userns: the mount's idmapping 352 * @fs_userns: the filesystem's idmapping 353 * @vfsgid : vfsgid to be mapped 354 * 355 * Map @vfsgid into the filesystem idmapping. This function has to be used in 356 * order to e.g. write @vfsgid to inode->i_gid. 357 * 358 * Return: @vfsgid mapped into the filesystem idmapping 359 */ 360static inline kgid_t from_vfsgid(struct user_namespace *mnt_userns, 361 struct user_namespace *fs_userns, 362 vfsgid_t vfsgid) 363{ 364 gid_t gid; 365 366 if (no_idmapping(mnt_userns, fs_userns)) 367 return AS_KGIDT(vfsgid); 368 gid = from_kgid(mnt_userns, AS_KGIDT(vfsgid)); 369 if (gid == (gid_t)-1) 370 return INVALID_GID; 371 if (initial_idmapping(fs_userns)) 372 return KGIDT_INIT(gid); 373 return make_kgid(fs_userns, gid); 374} 375 376/** 377 * mapped_kgid_user - map a user kgid into a mnt_userns 378 * @mnt_userns: the mount's idmapping 379 * @fs_userns: the filesystem's idmapping 380 * @kgid : kgid to be mapped 381 * 382 * Use the idmapping of @mnt_userns to remap a @kgid into @fs_userns. Use this 383 * function when preparing a @kgid to be written to disk or inode. 384 * 385 * If no_idmapping() determines that this is not an idmapped mount we can 386 * simply return @kgid unchanged. 387 * If initial_idmapping() tells us that the filesystem is not mounted with an 388 * idmapping we know the value of @kgid won't change when calling 389 * make_kgid() so we can simply retrieve the value via KGIDT_INIT() 390 * directly. 391 * 392 * Return: @kgid mapped according to @mnt_userns. 393 * If @kgid has no mapping in either @mnt_userns or @fs_userns INVALID_GID is 394 * returned. 395 */ 396static inline kgid_t mapped_kgid_user(struct user_namespace *mnt_userns, 397 struct user_namespace *fs_userns, 398 kgid_t kgid) 399{ 400 return from_vfsgid(mnt_userns, fs_userns, VFSGIDT_INIT(kgid)); 401} 402 403/** 404 * vfsgid_has_fsmapping - check whether a vfsgid maps into the filesystem 405 * @mnt_userns: the mount's idmapping 406 * @fs_userns: the filesystem's idmapping 407 * @vfsgid: vfsgid to be mapped 408 * 409 * Check whether @vfsgid has a mapping in the filesystem idmapping. Use this 410 * function to check whether the filesystem idmapping has a mapping for 411 * @vfsgid. 412 * 413 * Return: true if @vfsgid has a mapping in the filesystem, false if not. 414 */ 415static inline bool vfsgid_has_fsmapping(struct user_namespace *mnt_userns, 416 struct user_namespace *fs_userns, 417 vfsgid_t vfsgid) 418{ 419 return gid_valid(from_vfsgid(mnt_userns, fs_userns, vfsgid)); 420} 421 422/** 423 * vfsgid_into_kgid - convert vfsgid into kgid 424 * @vfsgid: the vfsgid to convert 425 * 426 * This can be used when a vfsgid is committed as a kgid. 427 * 428 * Return: a kgid with the value of @vfsgid 429 */ 430static inline kgid_t vfsgid_into_kgid(vfsgid_t vfsgid) 431{ 432 return AS_KGIDT(vfsgid); 433} 434 435/** 436 * mapped_fsuid - return caller's fsuid mapped up into a mnt_userns 437 * @mnt_userns: the mount's idmapping 438 * @fs_userns: the filesystem's idmapping 439 * 440 * Use this helper to initialize a new vfs or filesystem object based on 441 * the caller's fsuid. A common example is initializing the i_uid field of 442 * a newly allocated inode triggered by a creation event such as mkdir or 443 * O_CREAT. Other examples include the allocation of quotas for a specific 444 * user. 445 * 446 * Return: the caller's current fsuid mapped up according to @mnt_userns. 447 */ 448static inline kuid_t mapped_fsuid(struct user_namespace *mnt_userns, 449 struct user_namespace *fs_userns) 450{ 451 return from_vfsuid(mnt_userns, fs_userns, 452 VFSUIDT_INIT(current_fsuid())); 453} 454 455/** 456 * mapped_fsgid - return caller's fsgid mapped up into a mnt_userns 457 * @mnt_userns: the mount's idmapping 458 * @fs_userns: the filesystem's idmapping 459 * 460 * Use this helper to initialize a new vfs or filesystem object based on 461 * the caller's fsgid. A common example is initializing the i_gid field of 462 * a newly allocated inode triggered by a creation event such as mkdir or 463 * O_CREAT. Other examples include the allocation of quotas for a specific 464 * user. 465 * 466 * Return: the caller's current fsgid mapped up according to @mnt_userns. 467 */ 468static inline kgid_t mapped_fsgid(struct user_namespace *mnt_userns, 469 struct user_namespace *fs_userns) 470{ 471 return from_vfsgid(mnt_userns, fs_userns, 472 VFSGIDT_INIT(current_fsgid())); 473} 474 475#endif /* _LINUX_MNT_IDMAPPING_H */