1a793d79eSChristian Brauner /* SPDX-License-Identifier: GPL-2.0 */ 2a793d79eSChristian Brauner #ifndef _LINUX_MNT_IDMAPPING_H 3a793d79eSChristian Brauner #define _LINUX_MNT_IDMAPPING_H 4a793d79eSChristian Brauner 5a793d79eSChristian Brauner #include <linux/types.h> 6a793d79eSChristian Brauner #include <linux/uidgid.h> 7a793d79eSChristian Brauner 8a793d79eSChristian Brauner struct user_namespace; 9*1ac2a410SChristian Brauner /* 10*1ac2a410SChristian Brauner * Carries the initial idmapping of 0:0:4294967295 which is an identity 11*1ac2a410SChristian Brauner * mapping. This means that {g,u}id 0 is mapped to {g,u}id 0, {g,u}id 1 is 12*1ac2a410SChristian Brauner * mapped to {g,u}id 1, [...], {g,u}id 1000 to {g,u}id 1000, [...]. 13*1ac2a410SChristian Brauner */ 14a793d79eSChristian Brauner extern struct user_namespace init_user_ns; 15a793d79eSChristian Brauner 16a793d79eSChristian Brauner /** 17a793d79eSChristian Brauner * kuid_into_mnt - map a kuid down into a mnt_userns 18a793d79eSChristian Brauner * @mnt_userns: user namespace of the relevant mount 19a793d79eSChristian Brauner * @kuid: kuid to be mapped 20a793d79eSChristian Brauner * 21a793d79eSChristian Brauner * Return: @kuid mapped according to @mnt_userns. 22a793d79eSChristian Brauner * If @kuid has no mapping INVALID_UID is returned. 23a793d79eSChristian Brauner */ 24a793d79eSChristian Brauner static inline kuid_t kuid_into_mnt(struct user_namespace *mnt_userns, 25a793d79eSChristian Brauner kuid_t kuid) 26a793d79eSChristian Brauner { 27a793d79eSChristian Brauner return make_kuid(mnt_userns, __kuid_val(kuid)); 28a793d79eSChristian Brauner } 29a793d79eSChristian Brauner 30a793d79eSChristian Brauner /** 31a793d79eSChristian Brauner * kgid_into_mnt - map a kgid down into a mnt_userns 32a793d79eSChristian Brauner * @mnt_userns: user namespace of the relevant mount 33a793d79eSChristian Brauner * @kgid: kgid to be mapped 34a793d79eSChristian Brauner * 35a793d79eSChristian Brauner * Return: @kgid mapped according to @mnt_userns. 36a793d79eSChristian Brauner * If @kgid has no mapping INVALID_GID is returned. 37a793d79eSChristian Brauner */ 38a793d79eSChristian Brauner static inline kgid_t kgid_into_mnt(struct user_namespace *mnt_userns, 39a793d79eSChristian Brauner kgid_t kgid) 40a793d79eSChristian Brauner { 41a793d79eSChristian Brauner return make_kgid(mnt_userns, __kgid_val(kgid)); 42a793d79eSChristian Brauner } 43a793d79eSChristian Brauner 44a793d79eSChristian Brauner /** 45a793d79eSChristian Brauner * kuid_from_mnt - map a kuid up into a mnt_userns 46a793d79eSChristian Brauner * @mnt_userns: user namespace of the relevant mount 47a793d79eSChristian Brauner * @kuid: kuid to be mapped 48a793d79eSChristian Brauner * 49a793d79eSChristian Brauner * Return: @kuid mapped up according to @mnt_userns. 50a793d79eSChristian Brauner * If @kuid has no mapping INVALID_UID is returned. 51a793d79eSChristian Brauner */ 52a793d79eSChristian Brauner static inline kuid_t kuid_from_mnt(struct user_namespace *mnt_userns, 53a793d79eSChristian Brauner kuid_t kuid) 54a793d79eSChristian Brauner { 55a793d79eSChristian Brauner return KUIDT_INIT(from_kuid(mnt_userns, kuid)); 56a793d79eSChristian Brauner } 57a793d79eSChristian Brauner 58a793d79eSChristian Brauner /** 59a793d79eSChristian Brauner * kgid_from_mnt - map a kgid up into a mnt_userns 60a793d79eSChristian Brauner * @mnt_userns: user namespace of the relevant mount 61a793d79eSChristian Brauner * @kgid: kgid to be mapped 62a793d79eSChristian Brauner * 63a793d79eSChristian Brauner * Return: @kgid mapped up according to @mnt_userns. 64a793d79eSChristian Brauner * If @kgid has no mapping INVALID_GID is returned. 65a793d79eSChristian Brauner */ 66a793d79eSChristian Brauner static inline kgid_t kgid_from_mnt(struct user_namespace *mnt_userns, 67a793d79eSChristian Brauner kgid_t kgid) 68a793d79eSChristian Brauner { 69a793d79eSChristian Brauner return KGIDT_INIT(from_kgid(mnt_userns, kgid)); 70a793d79eSChristian Brauner } 71a793d79eSChristian Brauner 72a793d79eSChristian Brauner /** 73*1ac2a410SChristian Brauner * initial_idmapping - check whether this is the initial mapping 74*1ac2a410SChristian Brauner * @ns: idmapping to check 75*1ac2a410SChristian Brauner * 76*1ac2a410SChristian Brauner * Check whether this is the initial mapping, mapping 0 to 0, 1 to 1, 77*1ac2a410SChristian Brauner * [...], 1000 to 1000 [...]. 78*1ac2a410SChristian Brauner * 79*1ac2a410SChristian Brauner * Return: true if this is the initial mapping, false if not. 80*1ac2a410SChristian Brauner */ 81*1ac2a410SChristian Brauner static inline bool initial_idmapping(const struct user_namespace *ns) 82*1ac2a410SChristian Brauner { 83*1ac2a410SChristian Brauner return ns == &init_user_ns; 84*1ac2a410SChristian Brauner } 85*1ac2a410SChristian Brauner 86*1ac2a410SChristian Brauner /** 87*1ac2a410SChristian Brauner * no_idmapping - check whether we can skip remapping a kuid/gid 88*1ac2a410SChristian Brauner * @mnt_userns: the mount's idmapping 89*1ac2a410SChristian Brauner * @fs_userns: the filesystem's idmapping 90*1ac2a410SChristian Brauner * 91*1ac2a410SChristian Brauner * This function can be used to check whether a remapping between two 92*1ac2a410SChristian Brauner * idmappings is required. 93*1ac2a410SChristian Brauner * An idmapped mount is a mount that has an idmapping attached to it that 94*1ac2a410SChristian Brauner * is different from the filsystem's idmapping and the initial idmapping. 95*1ac2a410SChristian Brauner * If the initial mapping is used or the idmapping of the mount and the 96*1ac2a410SChristian Brauner * filesystem are identical no remapping is required. 97*1ac2a410SChristian Brauner * 98*1ac2a410SChristian Brauner * Return: true if remapping can be skipped, false if not. 99*1ac2a410SChristian Brauner */ 100*1ac2a410SChristian Brauner static inline bool no_idmapping(const struct user_namespace *mnt_userns, 101*1ac2a410SChristian Brauner const struct user_namespace *fs_userns) 102*1ac2a410SChristian Brauner { 103*1ac2a410SChristian Brauner return initial_idmapping(mnt_userns) || mnt_userns == fs_userns; 104*1ac2a410SChristian Brauner } 105*1ac2a410SChristian Brauner 106*1ac2a410SChristian Brauner /** 107*1ac2a410SChristian Brauner * mapped_kuid_fs - map a filesystem kuid into a mnt_userns 108*1ac2a410SChristian Brauner * @mnt_userns: the mount's idmapping 109*1ac2a410SChristian Brauner * @fs_userns: the filesystem's idmapping 110*1ac2a410SChristian Brauner * @kuid : kuid to be mapped 111*1ac2a410SChristian Brauner * 112*1ac2a410SChristian Brauner * Take a @kuid and remap it from @fs_userns into @mnt_userns. Use this 113*1ac2a410SChristian Brauner * function when preparing a @kuid to be reported to userspace. 114*1ac2a410SChristian Brauner * 115*1ac2a410SChristian Brauner * If no_idmapping() determines that this is not an idmapped mount we can 116*1ac2a410SChristian Brauner * simply return @kuid unchanged. 117*1ac2a410SChristian Brauner * If initial_idmapping() tells us that the filesystem is not mounted with an 118*1ac2a410SChristian Brauner * idmapping we know the value of @kuid won't change when calling 119*1ac2a410SChristian Brauner * from_kuid() so we can simply retrieve the value via __kuid_val() 120*1ac2a410SChristian Brauner * directly. 121*1ac2a410SChristian Brauner * 122*1ac2a410SChristian Brauner * Return: @kuid mapped according to @mnt_userns. 123*1ac2a410SChristian Brauner * If @kuid has no mapping in either @mnt_userns or @fs_userns INVALID_UID is 124*1ac2a410SChristian Brauner * returned. 125*1ac2a410SChristian Brauner */ 126*1ac2a410SChristian Brauner static inline kuid_t mapped_kuid_fs(struct user_namespace *mnt_userns, 127*1ac2a410SChristian Brauner struct user_namespace *fs_userns, 128*1ac2a410SChristian Brauner kuid_t kuid) 129*1ac2a410SChristian Brauner { 130*1ac2a410SChristian Brauner uid_t uid; 131*1ac2a410SChristian Brauner 132*1ac2a410SChristian Brauner if (no_idmapping(mnt_userns, fs_userns)) 133*1ac2a410SChristian Brauner return kuid; 134*1ac2a410SChristian Brauner if (initial_idmapping(fs_userns)) 135*1ac2a410SChristian Brauner uid = __kuid_val(kuid); 136*1ac2a410SChristian Brauner else 137*1ac2a410SChristian Brauner uid = from_kuid(fs_userns, kuid); 138*1ac2a410SChristian Brauner if (uid == (uid_t)-1) 139*1ac2a410SChristian Brauner return INVALID_UID; 140*1ac2a410SChristian Brauner return make_kuid(mnt_userns, uid); 141*1ac2a410SChristian Brauner } 142*1ac2a410SChristian Brauner 143*1ac2a410SChristian Brauner /** 144*1ac2a410SChristian Brauner * mapped_kgid_fs - map a filesystem kgid into a mnt_userns 145*1ac2a410SChristian Brauner * @mnt_userns: the mount's idmapping 146*1ac2a410SChristian Brauner * @fs_userns: the filesystem's idmapping 147*1ac2a410SChristian Brauner * @kgid : kgid to be mapped 148*1ac2a410SChristian Brauner * 149*1ac2a410SChristian Brauner * Take a @kgid and remap it from @fs_userns into @mnt_userns. Use this 150*1ac2a410SChristian Brauner * function when preparing a @kgid to be reported to userspace. 151*1ac2a410SChristian Brauner * 152*1ac2a410SChristian Brauner * If no_idmapping() determines that this is not an idmapped mount we can 153*1ac2a410SChristian Brauner * simply return @kgid unchanged. 154*1ac2a410SChristian Brauner * If initial_idmapping() tells us that the filesystem is not mounted with an 155*1ac2a410SChristian Brauner * idmapping we know the value of @kgid won't change when calling 156*1ac2a410SChristian Brauner * from_kgid() so we can simply retrieve the value via __kgid_val() 157*1ac2a410SChristian Brauner * directly. 158*1ac2a410SChristian Brauner * 159*1ac2a410SChristian Brauner * Return: @kgid mapped according to @mnt_userns. 160*1ac2a410SChristian Brauner * If @kgid has no mapping in either @mnt_userns or @fs_userns INVALID_GID is 161*1ac2a410SChristian Brauner * returned. 162*1ac2a410SChristian Brauner */ 163*1ac2a410SChristian Brauner static inline kgid_t mapped_kgid_fs(struct user_namespace *mnt_userns, 164*1ac2a410SChristian Brauner struct user_namespace *fs_userns, 165*1ac2a410SChristian Brauner kgid_t kgid) 166*1ac2a410SChristian Brauner { 167*1ac2a410SChristian Brauner gid_t gid; 168*1ac2a410SChristian Brauner 169*1ac2a410SChristian Brauner if (no_idmapping(mnt_userns, fs_userns)) 170*1ac2a410SChristian Brauner return kgid; 171*1ac2a410SChristian Brauner if (initial_idmapping(fs_userns)) 172*1ac2a410SChristian Brauner gid = __kgid_val(kgid); 173*1ac2a410SChristian Brauner else 174*1ac2a410SChristian Brauner gid = from_kgid(fs_userns, kgid); 175*1ac2a410SChristian Brauner if (gid == (gid_t)-1) 176*1ac2a410SChristian Brauner return INVALID_GID; 177*1ac2a410SChristian Brauner return make_kgid(mnt_userns, gid); 178*1ac2a410SChristian Brauner } 179*1ac2a410SChristian Brauner 180*1ac2a410SChristian Brauner /** 181*1ac2a410SChristian Brauner * mapped_kuid_user - map a user kuid into a mnt_userns 182*1ac2a410SChristian Brauner * @mnt_userns: the mount's idmapping 183*1ac2a410SChristian Brauner * @fs_userns: the filesystem's idmapping 184*1ac2a410SChristian Brauner * @kuid : kuid to be mapped 185*1ac2a410SChristian Brauner * 186*1ac2a410SChristian Brauner * Use the idmapping of @mnt_userns to remap a @kuid into @fs_userns. Use this 187*1ac2a410SChristian Brauner * function when preparing a @kuid to be written to disk or inode. 188*1ac2a410SChristian Brauner * 189*1ac2a410SChristian Brauner * If no_idmapping() determines that this is not an idmapped mount we can 190*1ac2a410SChristian Brauner * simply return @kuid unchanged. 191*1ac2a410SChristian Brauner * If initial_idmapping() tells us that the filesystem is not mounted with an 192*1ac2a410SChristian Brauner * idmapping we know the value of @kuid won't change when calling 193*1ac2a410SChristian Brauner * make_kuid() so we can simply retrieve the value via KUIDT_INIT() 194*1ac2a410SChristian Brauner * directly. 195*1ac2a410SChristian Brauner * 196*1ac2a410SChristian Brauner * Return: @kuid mapped according to @mnt_userns. 197*1ac2a410SChristian Brauner * If @kuid has no mapping in either @mnt_userns or @fs_userns INVALID_UID is 198*1ac2a410SChristian Brauner * returned. 199*1ac2a410SChristian Brauner */ 200*1ac2a410SChristian Brauner static inline kuid_t mapped_kuid_user(struct user_namespace *mnt_userns, 201*1ac2a410SChristian Brauner struct user_namespace *fs_userns, 202*1ac2a410SChristian Brauner kuid_t kuid) 203*1ac2a410SChristian Brauner { 204*1ac2a410SChristian Brauner uid_t uid; 205*1ac2a410SChristian Brauner 206*1ac2a410SChristian Brauner if (no_idmapping(mnt_userns, fs_userns)) 207*1ac2a410SChristian Brauner return kuid; 208*1ac2a410SChristian Brauner uid = from_kuid(mnt_userns, kuid); 209*1ac2a410SChristian Brauner if (uid == (uid_t)-1) 210*1ac2a410SChristian Brauner return INVALID_UID; 211*1ac2a410SChristian Brauner if (initial_idmapping(fs_userns)) 212*1ac2a410SChristian Brauner return KUIDT_INIT(uid); 213*1ac2a410SChristian Brauner return make_kuid(fs_userns, uid); 214*1ac2a410SChristian Brauner } 215*1ac2a410SChristian Brauner 216*1ac2a410SChristian Brauner /** 217*1ac2a410SChristian Brauner * mapped_kgid_user - map a user kgid into a mnt_userns 218*1ac2a410SChristian Brauner * @mnt_userns: the mount's idmapping 219*1ac2a410SChristian Brauner * @fs_userns: the filesystem's idmapping 220*1ac2a410SChristian Brauner * @kgid : kgid to be mapped 221*1ac2a410SChristian Brauner * 222*1ac2a410SChristian Brauner * Use the idmapping of @mnt_userns to remap a @kgid into @fs_userns. Use this 223*1ac2a410SChristian Brauner * function when preparing a @kgid to be written to disk or inode. 224*1ac2a410SChristian Brauner * 225*1ac2a410SChristian Brauner * If no_idmapping() determines that this is not an idmapped mount we can 226*1ac2a410SChristian Brauner * simply return @kgid unchanged. 227*1ac2a410SChristian Brauner * If initial_idmapping() tells us that the filesystem is not mounted with an 228*1ac2a410SChristian Brauner * idmapping we know the value of @kgid won't change when calling 229*1ac2a410SChristian Brauner * make_kgid() so we can simply retrieve the value via KGIDT_INIT() 230*1ac2a410SChristian Brauner * directly. 231*1ac2a410SChristian Brauner * 232*1ac2a410SChristian Brauner * Return: @kgid mapped according to @mnt_userns. 233*1ac2a410SChristian Brauner * If @kgid has no mapping in either @mnt_userns or @fs_userns INVALID_GID is 234*1ac2a410SChristian Brauner * returned. 235*1ac2a410SChristian Brauner */ 236*1ac2a410SChristian Brauner static inline kgid_t mapped_kgid_user(struct user_namespace *mnt_userns, 237*1ac2a410SChristian Brauner struct user_namespace *fs_userns, 238*1ac2a410SChristian Brauner kgid_t kgid) 239*1ac2a410SChristian Brauner { 240*1ac2a410SChristian Brauner gid_t gid; 241*1ac2a410SChristian Brauner 242*1ac2a410SChristian Brauner if (no_idmapping(mnt_userns, fs_userns)) 243*1ac2a410SChristian Brauner return kgid; 244*1ac2a410SChristian Brauner gid = from_kgid(mnt_userns, kgid); 245*1ac2a410SChristian Brauner if (gid == (gid_t)-1) 246*1ac2a410SChristian Brauner return INVALID_GID; 247*1ac2a410SChristian Brauner if (initial_idmapping(fs_userns)) 248*1ac2a410SChristian Brauner return KGIDT_INIT(gid); 249*1ac2a410SChristian Brauner return make_kgid(fs_userns, gid); 250*1ac2a410SChristian Brauner } 251*1ac2a410SChristian Brauner 252*1ac2a410SChristian Brauner /** 253a793d79eSChristian Brauner * mapped_fsuid - return caller's fsuid mapped up into a mnt_userns 254*1ac2a410SChristian Brauner * @mnt_userns: the mount's idmapping 255a793d79eSChristian Brauner * 256a793d79eSChristian Brauner * Use this helper to initialize a new vfs or filesystem object based on 257a793d79eSChristian Brauner * the caller's fsuid. A common example is initializing the i_uid field of 258a793d79eSChristian Brauner * a newly allocated inode triggered by a creation event such as mkdir or 259a793d79eSChristian Brauner * O_CREAT. Other examples include the allocation of quotas for a specific 260a793d79eSChristian Brauner * user. 261a793d79eSChristian Brauner * 262a793d79eSChristian Brauner * Return: the caller's current fsuid mapped up according to @mnt_userns. 263a793d79eSChristian Brauner */ 264a793d79eSChristian Brauner static inline kuid_t mapped_fsuid(struct user_namespace *mnt_userns) 265a793d79eSChristian Brauner { 266*1ac2a410SChristian Brauner return mapped_kuid_user(mnt_userns, &init_user_ns, current_fsuid()); 267a793d79eSChristian Brauner } 268a793d79eSChristian Brauner 269a793d79eSChristian Brauner /** 270a793d79eSChristian Brauner * mapped_fsgid - return caller's fsgid mapped up into a mnt_userns 271*1ac2a410SChristian Brauner * @mnt_userns: the mount's idmapping 272a793d79eSChristian Brauner * 273a793d79eSChristian Brauner * Use this helper to initialize a new vfs or filesystem object based on 274a793d79eSChristian Brauner * the caller's fsgid. A common example is initializing the i_gid field of 275a793d79eSChristian Brauner * a newly allocated inode triggered by a creation event such as mkdir or 276a793d79eSChristian Brauner * O_CREAT. Other examples include the allocation of quotas for a specific 277a793d79eSChristian Brauner * user. 278a793d79eSChristian Brauner * 279a793d79eSChristian Brauner * Return: the caller's current fsgid mapped up according to @mnt_userns. 280a793d79eSChristian Brauner */ 281a793d79eSChristian Brauner static inline kgid_t mapped_fsgid(struct user_namespace *mnt_userns) 282a793d79eSChristian Brauner { 283*1ac2a410SChristian Brauner return mapped_kgid_user(mnt_userns, &init_user_ns, current_fsgid()); 284a793d79eSChristian Brauner } 285a793d79eSChristian Brauner 286a793d79eSChristian Brauner #endif /* _LINUX_MNT_IDMAPPING_H */ 287