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; 91ac2a410SChristian Brauner /* 101ac2a410SChristian Brauner * Carries the initial idmapping of 0:0:4294967295 which is an identity 111ac2a410SChristian Brauner * mapping. This means that {g,u}id 0 is mapped to {g,u}id 0, {g,u}id 1 is 121ac2a410SChristian Brauner * mapped to {g,u}id 1, [...], {g,u}id 1000 to {g,u}id 1000, [...]. 131ac2a410SChristian Brauner */ 14a793d79eSChristian Brauner extern struct user_namespace init_user_ns; 15a793d79eSChristian Brauner 16a793d79eSChristian Brauner /** 171ac2a410SChristian Brauner * initial_idmapping - check whether this is the initial mapping 181ac2a410SChristian Brauner * @ns: idmapping to check 191ac2a410SChristian Brauner * 201ac2a410SChristian Brauner * Check whether this is the initial mapping, mapping 0 to 0, 1 to 1, 211ac2a410SChristian Brauner * [...], 1000 to 1000 [...]. 221ac2a410SChristian Brauner * 231ac2a410SChristian Brauner * Return: true if this is the initial mapping, false if not. 241ac2a410SChristian Brauner */ 251ac2a410SChristian Brauner static inline bool initial_idmapping(const struct user_namespace *ns) 261ac2a410SChristian Brauner { 271ac2a410SChristian Brauner return ns == &init_user_ns; 281ac2a410SChristian Brauner } 291ac2a410SChristian Brauner 301ac2a410SChristian Brauner /** 311ac2a410SChristian Brauner * no_idmapping - check whether we can skip remapping a kuid/gid 321ac2a410SChristian Brauner * @mnt_userns: the mount's idmapping 331ac2a410SChristian Brauner * @fs_userns: the filesystem's idmapping 341ac2a410SChristian Brauner * 351ac2a410SChristian Brauner * This function can be used to check whether a remapping between two 361ac2a410SChristian Brauner * idmappings is required. 371ac2a410SChristian Brauner * An idmapped mount is a mount that has an idmapping attached to it that 381ac2a410SChristian Brauner * is different from the filsystem's idmapping and the initial idmapping. 391ac2a410SChristian Brauner * If the initial mapping is used or the idmapping of the mount and the 401ac2a410SChristian Brauner * filesystem are identical no remapping is required. 411ac2a410SChristian Brauner * 421ac2a410SChristian Brauner * Return: true if remapping can be skipped, false if not. 431ac2a410SChristian Brauner */ 441ac2a410SChristian Brauner static inline bool no_idmapping(const struct user_namespace *mnt_userns, 451ac2a410SChristian Brauner const struct user_namespace *fs_userns) 461ac2a410SChristian Brauner { 471ac2a410SChristian Brauner return initial_idmapping(mnt_userns) || mnt_userns == fs_userns; 481ac2a410SChristian Brauner } 491ac2a410SChristian Brauner 501ac2a410SChristian Brauner /** 511ac2a410SChristian Brauner * mapped_kuid_fs - map a filesystem kuid into a mnt_userns 521ac2a410SChristian Brauner * @mnt_userns: the mount's idmapping 531ac2a410SChristian Brauner * @fs_userns: the filesystem's idmapping 541ac2a410SChristian Brauner * @kuid : kuid to be mapped 551ac2a410SChristian Brauner * 561ac2a410SChristian Brauner * Take a @kuid and remap it from @fs_userns into @mnt_userns. Use this 571ac2a410SChristian Brauner * function when preparing a @kuid to be reported to userspace. 581ac2a410SChristian Brauner * 591ac2a410SChristian Brauner * If no_idmapping() determines that this is not an idmapped mount we can 601ac2a410SChristian Brauner * simply return @kuid unchanged. 611ac2a410SChristian Brauner * If initial_idmapping() tells us that the filesystem is not mounted with an 621ac2a410SChristian Brauner * idmapping we know the value of @kuid won't change when calling 631ac2a410SChristian Brauner * from_kuid() so we can simply retrieve the value via __kuid_val() 641ac2a410SChristian Brauner * directly. 651ac2a410SChristian Brauner * 661ac2a410SChristian Brauner * Return: @kuid mapped according to @mnt_userns. 671ac2a410SChristian Brauner * If @kuid has no mapping in either @mnt_userns or @fs_userns INVALID_UID is 681ac2a410SChristian Brauner * returned. 691ac2a410SChristian Brauner */ 701ac2a410SChristian Brauner static inline kuid_t mapped_kuid_fs(struct user_namespace *mnt_userns, 711ac2a410SChristian Brauner struct user_namespace *fs_userns, 721ac2a410SChristian Brauner kuid_t kuid) 731ac2a410SChristian Brauner { 741ac2a410SChristian Brauner uid_t uid; 751ac2a410SChristian Brauner 761ac2a410SChristian Brauner if (no_idmapping(mnt_userns, fs_userns)) 771ac2a410SChristian Brauner return kuid; 781ac2a410SChristian Brauner if (initial_idmapping(fs_userns)) 791ac2a410SChristian Brauner uid = __kuid_val(kuid); 801ac2a410SChristian Brauner else 811ac2a410SChristian Brauner uid = from_kuid(fs_userns, kuid); 821ac2a410SChristian Brauner if (uid == (uid_t)-1) 831ac2a410SChristian Brauner return INVALID_UID; 841ac2a410SChristian Brauner return make_kuid(mnt_userns, uid); 851ac2a410SChristian Brauner } 861ac2a410SChristian Brauner 871ac2a410SChristian Brauner /** 881ac2a410SChristian Brauner * mapped_kgid_fs - map a filesystem kgid into a mnt_userns 891ac2a410SChristian Brauner * @mnt_userns: the mount's idmapping 901ac2a410SChristian Brauner * @fs_userns: the filesystem's idmapping 911ac2a410SChristian Brauner * @kgid : kgid to be mapped 921ac2a410SChristian Brauner * 931ac2a410SChristian Brauner * Take a @kgid and remap it from @fs_userns into @mnt_userns. Use this 941ac2a410SChristian Brauner * function when preparing a @kgid to be reported to userspace. 951ac2a410SChristian Brauner * 961ac2a410SChristian Brauner * If no_idmapping() determines that this is not an idmapped mount we can 971ac2a410SChristian Brauner * simply return @kgid unchanged. 981ac2a410SChristian Brauner * If initial_idmapping() tells us that the filesystem is not mounted with an 991ac2a410SChristian Brauner * idmapping we know the value of @kgid won't change when calling 1001ac2a410SChristian Brauner * from_kgid() so we can simply retrieve the value via __kgid_val() 1011ac2a410SChristian Brauner * directly. 1021ac2a410SChristian Brauner * 1031ac2a410SChristian Brauner * Return: @kgid mapped according to @mnt_userns. 1041ac2a410SChristian Brauner * If @kgid has no mapping in either @mnt_userns or @fs_userns INVALID_GID is 1051ac2a410SChristian Brauner * returned. 1061ac2a410SChristian Brauner */ 1071ac2a410SChristian Brauner static inline kgid_t mapped_kgid_fs(struct user_namespace *mnt_userns, 1081ac2a410SChristian Brauner struct user_namespace *fs_userns, 1091ac2a410SChristian Brauner kgid_t kgid) 1101ac2a410SChristian Brauner { 1111ac2a410SChristian Brauner gid_t gid; 1121ac2a410SChristian Brauner 1131ac2a410SChristian Brauner if (no_idmapping(mnt_userns, fs_userns)) 1141ac2a410SChristian Brauner return kgid; 1151ac2a410SChristian Brauner if (initial_idmapping(fs_userns)) 1161ac2a410SChristian Brauner gid = __kgid_val(kgid); 1171ac2a410SChristian Brauner else 1181ac2a410SChristian Brauner gid = from_kgid(fs_userns, kgid); 1191ac2a410SChristian Brauner if (gid == (gid_t)-1) 1201ac2a410SChristian Brauner return INVALID_GID; 1211ac2a410SChristian Brauner return make_kgid(mnt_userns, gid); 1221ac2a410SChristian Brauner } 1231ac2a410SChristian Brauner 1241ac2a410SChristian Brauner /** 1251ac2a410SChristian Brauner * mapped_kuid_user - map a user kuid into a mnt_userns 1261ac2a410SChristian Brauner * @mnt_userns: the mount's idmapping 1271ac2a410SChristian Brauner * @fs_userns: the filesystem's idmapping 1281ac2a410SChristian Brauner * @kuid : kuid to be mapped 1291ac2a410SChristian Brauner * 1301ac2a410SChristian Brauner * Use the idmapping of @mnt_userns to remap a @kuid into @fs_userns. Use this 1311ac2a410SChristian Brauner * function when preparing a @kuid to be written to disk or inode. 1321ac2a410SChristian Brauner * 1331ac2a410SChristian Brauner * If no_idmapping() determines that this is not an idmapped mount we can 1341ac2a410SChristian Brauner * simply return @kuid unchanged. 1351ac2a410SChristian Brauner * If initial_idmapping() tells us that the filesystem is not mounted with an 1361ac2a410SChristian Brauner * idmapping we know the value of @kuid won't change when calling 1371ac2a410SChristian Brauner * make_kuid() so we can simply retrieve the value via KUIDT_INIT() 1381ac2a410SChristian Brauner * directly. 1391ac2a410SChristian Brauner * 1401ac2a410SChristian Brauner * Return: @kuid mapped according to @mnt_userns. 1411ac2a410SChristian Brauner * If @kuid has no mapping in either @mnt_userns or @fs_userns INVALID_UID is 1421ac2a410SChristian Brauner * returned. 1431ac2a410SChristian Brauner */ 1441ac2a410SChristian Brauner static inline kuid_t mapped_kuid_user(struct user_namespace *mnt_userns, 1451ac2a410SChristian Brauner struct user_namespace *fs_userns, 1461ac2a410SChristian Brauner kuid_t kuid) 1471ac2a410SChristian Brauner { 1481ac2a410SChristian Brauner uid_t uid; 1491ac2a410SChristian Brauner 1501ac2a410SChristian Brauner if (no_idmapping(mnt_userns, fs_userns)) 1511ac2a410SChristian Brauner return kuid; 1521ac2a410SChristian Brauner uid = from_kuid(mnt_userns, kuid); 1531ac2a410SChristian Brauner if (uid == (uid_t)-1) 1541ac2a410SChristian Brauner return INVALID_UID; 1551ac2a410SChristian Brauner if (initial_idmapping(fs_userns)) 1561ac2a410SChristian Brauner return KUIDT_INIT(uid); 1571ac2a410SChristian Brauner return make_kuid(fs_userns, uid); 1581ac2a410SChristian Brauner } 1591ac2a410SChristian Brauner 1601ac2a410SChristian Brauner /** 1611ac2a410SChristian Brauner * mapped_kgid_user - map a user kgid into a mnt_userns 1621ac2a410SChristian Brauner * @mnt_userns: the mount's idmapping 1631ac2a410SChristian Brauner * @fs_userns: the filesystem's idmapping 1641ac2a410SChristian Brauner * @kgid : kgid to be mapped 1651ac2a410SChristian Brauner * 1661ac2a410SChristian Brauner * Use the idmapping of @mnt_userns to remap a @kgid into @fs_userns. Use this 1671ac2a410SChristian Brauner * function when preparing a @kgid to be written to disk or inode. 1681ac2a410SChristian Brauner * 1691ac2a410SChristian Brauner * If no_idmapping() determines that this is not an idmapped mount we can 1701ac2a410SChristian Brauner * simply return @kgid unchanged. 1711ac2a410SChristian Brauner * If initial_idmapping() tells us that the filesystem is not mounted with an 1721ac2a410SChristian Brauner * idmapping we know the value of @kgid won't change when calling 1731ac2a410SChristian Brauner * make_kgid() so we can simply retrieve the value via KGIDT_INIT() 1741ac2a410SChristian Brauner * directly. 1751ac2a410SChristian Brauner * 1761ac2a410SChristian Brauner * Return: @kgid mapped according to @mnt_userns. 1771ac2a410SChristian Brauner * If @kgid has no mapping in either @mnt_userns or @fs_userns INVALID_GID is 1781ac2a410SChristian Brauner * returned. 1791ac2a410SChristian Brauner */ 1801ac2a410SChristian Brauner static inline kgid_t mapped_kgid_user(struct user_namespace *mnt_userns, 1811ac2a410SChristian Brauner struct user_namespace *fs_userns, 1821ac2a410SChristian Brauner kgid_t kgid) 1831ac2a410SChristian Brauner { 1841ac2a410SChristian Brauner gid_t gid; 1851ac2a410SChristian Brauner 1861ac2a410SChristian Brauner if (no_idmapping(mnt_userns, fs_userns)) 1871ac2a410SChristian Brauner return kgid; 1881ac2a410SChristian Brauner gid = from_kgid(mnt_userns, kgid); 1891ac2a410SChristian Brauner if (gid == (gid_t)-1) 1901ac2a410SChristian Brauner return INVALID_GID; 1911ac2a410SChristian Brauner if (initial_idmapping(fs_userns)) 1921ac2a410SChristian Brauner return KGIDT_INIT(gid); 1931ac2a410SChristian Brauner return make_kgid(fs_userns, gid); 1941ac2a410SChristian Brauner } 1951ac2a410SChristian Brauner 1961ac2a410SChristian Brauner /** 197a793d79eSChristian Brauner * mapped_fsuid - return caller's fsuid mapped up into a mnt_userns 1981ac2a410SChristian Brauner * @mnt_userns: the mount's idmapping 199*209188ceSChristian Brauner * @fs_userns: the filesystem's idmapping 200a793d79eSChristian Brauner * 201a793d79eSChristian Brauner * Use this helper to initialize a new vfs or filesystem object based on 202a793d79eSChristian Brauner * the caller's fsuid. A common example is initializing the i_uid field of 203a793d79eSChristian Brauner * a newly allocated inode triggered by a creation event such as mkdir or 204a793d79eSChristian Brauner * O_CREAT. Other examples include the allocation of quotas for a specific 205a793d79eSChristian Brauner * user. 206a793d79eSChristian Brauner * 207a793d79eSChristian Brauner * Return: the caller's current fsuid mapped up according to @mnt_userns. 208a793d79eSChristian Brauner */ 209*209188ceSChristian Brauner static inline kuid_t mapped_fsuid(struct user_namespace *mnt_userns, 210*209188ceSChristian Brauner struct user_namespace *fs_userns) 211a793d79eSChristian Brauner { 212*209188ceSChristian Brauner return mapped_kuid_user(mnt_userns, fs_userns, current_fsuid()); 213a793d79eSChristian Brauner } 214a793d79eSChristian Brauner 215a793d79eSChristian Brauner /** 216a793d79eSChristian Brauner * mapped_fsgid - return caller's fsgid mapped up into a mnt_userns 2171ac2a410SChristian Brauner * @mnt_userns: the mount's idmapping 218*209188ceSChristian Brauner * @fs_userns: the filesystem's idmapping 219a793d79eSChristian Brauner * 220a793d79eSChristian Brauner * Use this helper to initialize a new vfs or filesystem object based on 221a793d79eSChristian Brauner * the caller's fsgid. A common example is initializing the i_gid field of 222a793d79eSChristian Brauner * a newly allocated inode triggered by a creation event such as mkdir or 223a793d79eSChristian Brauner * O_CREAT. Other examples include the allocation of quotas for a specific 224a793d79eSChristian Brauner * user. 225a793d79eSChristian Brauner * 226a793d79eSChristian Brauner * Return: the caller's current fsgid mapped up according to @mnt_userns. 227a793d79eSChristian Brauner */ 228*209188ceSChristian Brauner static inline kgid_t mapped_fsgid(struct user_namespace *mnt_userns, 229*209188ceSChristian Brauner struct user_namespace *fs_userns) 230a793d79eSChristian Brauner { 231*209188ceSChristian Brauner return mapped_kgid_user(mnt_userns, fs_userns, current_fsgid()); 232a793d79eSChristian Brauner } 233a793d79eSChristian Brauner 234a793d79eSChristian Brauner #endif /* _LINUX_MNT_IDMAPPING_H */ 235