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 8256c8aedSChristian Brauner struct mnt_idmap; 9a793d79eSChristian Brauner struct user_namespace; 10256c8aedSChristian Brauner 11256c8aedSChristian Brauner extern struct mnt_idmap nop_mnt_idmap; 12a793d79eSChristian Brauner extern struct user_namespace init_user_ns; 13a793d79eSChristian Brauner 141e5267cdSChristian Brauner typedef struct { 151e5267cdSChristian Brauner uid_t val; 161e5267cdSChristian Brauner } vfsuid_t; 171e5267cdSChristian Brauner 181e5267cdSChristian Brauner typedef struct { 191e5267cdSChristian Brauner gid_t val; 201e5267cdSChristian Brauner } vfsgid_t; 211e5267cdSChristian Brauner 2245c31150SChristian Brauner static_assert(sizeof(vfsuid_t) == sizeof(kuid_t)); 2345c31150SChristian Brauner static_assert(sizeof(vfsgid_t) == sizeof(kgid_t)); 2445c31150SChristian Brauner static_assert(offsetof(vfsuid_t, val) == offsetof(kuid_t, val)); 2545c31150SChristian Brauner static_assert(offsetof(vfsgid_t, val) == offsetof(kgid_t, val)); 2645c31150SChristian Brauner 271e5267cdSChristian Brauner #ifdef CONFIG_MULTIUSER 281e5267cdSChristian Brauner static inline uid_t __vfsuid_val(vfsuid_t uid) 291e5267cdSChristian Brauner { 301e5267cdSChristian Brauner return uid.val; 311e5267cdSChristian Brauner } 321e5267cdSChristian Brauner 331e5267cdSChristian Brauner static inline gid_t __vfsgid_val(vfsgid_t gid) 341e5267cdSChristian Brauner { 351e5267cdSChristian Brauner return gid.val; 361e5267cdSChristian Brauner } 371e5267cdSChristian Brauner #else 381e5267cdSChristian Brauner static inline uid_t __vfsuid_val(vfsuid_t uid) 391e5267cdSChristian Brauner { 401e5267cdSChristian Brauner return 0; 411e5267cdSChristian Brauner } 421e5267cdSChristian Brauner 431e5267cdSChristian Brauner static inline gid_t __vfsgid_val(vfsgid_t gid) 441e5267cdSChristian Brauner { 451e5267cdSChristian Brauner return 0; 461e5267cdSChristian Brauner } 471e5267cdSChristian Brauner #endif 481e5267cdSChristian Brauner 491e5267cdSChristian Brauner static inline bool vfsuid_valid(vfsuid_t uid) 501e5267cdSChristian Brauner { 511e5267cdSChristian Brauner return __vfsuid_val(uid) != (uid_t)-1; 521e5267cdSChristian Brauner } 531e5267cdSChristian Brauner 541e5267cdSChristian Brauner static inline bool vfsgid_valid(vfsgid_t gid) 551e5267cdSChristian Brauner { 561e5267cdSChristian Brauner return __vfsgid_val(gid) != (gid_t)-1; 571e5267cdSChristian Brauner } 581e5267cdSChristian Brauner 591e5267cdSChristian Brauner static inline bool vfsuid_eq(vfsuid_t left, vfsuid_t right) 601e5267cdSChristian Brauner { 614d0548a7SSeth Forshee return vfsuid_valid(left) && __vfsuid_val(left) == __vfsuid_val(right); 621e5267cdSChristian Brauner } 631e5267cdSChristian Brauner 641e5267cdSChristian Brauner static inline bool vfsgid_eq(vfsgid_t left, vfsgid_t right) 651e5267cdSChristian Brauner { 664d0548a7SSeth Forshee return vfsgid_valid(left) && __vfsgid_val(left) == __vfsgid_val(right); 671e5267cdSChristian Brauner } 681e5267cdSChristian Brauner 691e5267cdSChristian Brauner /** 701e5267cdSChristian Brauner * vfsuid_eq_kuid - check whether kuid and vfsuid have the same value 711e5267cdSChristian Brauner * @vfsuid: the vfsuid to compare 7277940f0dSChristian Brauner * @kuid: the kuid to compare 731e5267cdSChristian Brauner * 7477940f0dSChristian Brauner * Check whether @vfsuid and @kuid have the same values. 751e5267cdSChristian Brauner * 7677940f0dSChristian Brauner * Return: true if @vfsuid and @kuid have the same value, false if not. 774d0548a7SSeth Forshee * Comparison between two invalid uids returns false. 781e5267cdSChristian Brauner */ 791e5267cdSChristian Brauner static inline bool vfsuid_eq_kuid(vfsuid_t vfsuid, kuid_t kuid) 801e5267cdSChristian Brauner { 814d0548a7SSeth Forshee return vfsuid_valid(vfsuid) && __vfsuid_val(vfsuid) == __kuid_val(kuid); 821e5267cdSChristian Brauner } 831e5267cdSChristian Brauner 841e5267cdSChristian Brauner /** 851e5267cdSChristian Brauner * vfsgid_eq_kgid - check whether kgid and vfsgid have the same value 861e5267cdSChristian Brauner * @vfsgid: the vfsgid to compare 8777940f0dSChristian Brauner * @kgid: the kgid to compare 881e5267cdSChristian Brauner * 8977940f0dSChristian Brauner * Check whether @vfsgid and @kgid have the same values. 901e5267cdSChristian Brauner * 9177940f0dSChristian Brauner * Return: true if @vfsgid and @kgid have the same value, false if not. 924d0548a7SSeth Forshee * Comparison between two invalid gids returns false. 931e5267cdSChristian Brauner */ 9477940f0dSChristian Brauner static inline bool vfsgid_eq_kgid(vfsgid_t vfsgid, kgid_t kgid) 951e5267cdSChristian Brauner { 964d0548a7SSeth Forshee return vfsgid_valid(vfsgid) && __vfsgid_val(vfsgid) == __kgid_val(kgid); 971e5267cdSChristian Brauner } 981e5267cdSChristian Brauner 991e5267cdSChristian Brauner /* 1001e5267cdSChristian Brauner * vfs{g,u}ids are created from k{g,u}ids. 1011e5267cdSChristian Brauner * We don't allow them to be created from regular {u,g}id. 1021e5267cdSChristian Brauner */ 1031e5267cdSChristian Brauner #define VFSUIDT_INIT(val) (vfsuid_t){ __kuid_val(val) } 1041e5267cdSChristian Brauner #define VFSGIDT_INIT(val) (vfsgid_t){ __kgid_val(val) } 1051e5267cdSChristian Brauner 1061e5267cdSChristian Brauner #define INVALID_VFSUID VFSUIDT_INIT(INVALID_UID) 1071e5267cdSChristian Brauner #define INVALID_VFSGID VFSGIDT_INIT(INVALID_GID) 1081e5267cdSChristian Brauner 1091e5267cdSChristian Brauner /* 1101e5267cdSChristian Brauner * Allow a vfs{g,u}id to be used as a k{g,u}id where we want to compare 1111e5267cdSChristian Brauner * whether the mapped value is identical to value of a k{g,u}id. 1121e5267cdSChristian Brauner */ 1131e5267cdSChristian Brauner #define AS_KUIDT(val) (kuid_t){ __vfsuid_val(val) } 1141e5267cdSChristian Brauner #define AS_KGIDT(val) (kgid_t){ __vfsgid_val(val) } 1151e5267cdSChristian Brauner 116*3707d84cSChristian Brauner int vfsgid_in_group_p(vfsgid_t vfsgid); 1171e5267cdSChristian Brauner 118*3707d84cSChristian Brauner vfsuid_t make_vfsuid(struct mnt_idmap *idmap, 119*3707d84cSChristian Brauner struct user_namespace *fs_userns, kuid_t kuid); 1201ac2a410SChristian Brauner 121*3707d84cSChristian Brauner vfsgid_t make_vfsgid(struct mnt_idmap *idmap, 122*3707d84cSChristian Brauner struct user_namespace *fs_userns, kgid_t kgid); 1231ac2a410SChristian Brauner 124*3707d84cSChristian Brauner kuid_t from_vfsuid(struct mnt_idmap *idmap, 125*3707d84cSChristian Brauner struct user_namespace *fs_userns, vfsuid_t vfsuid); 1261e5267cdSChristian Brauner 127*3707d84cSChristian Brauner kgid_t from_vfsgid(struct mnt_idmap *idmap, 128*3707d84cSChristian Brauner struct user_namespace *fs_userns, vfsgid_t vfsgid); 1291ac2a410SChristian Brauner 1301ac2a410SChristian Brauner /** 1311e5267cdSChristian Brauner * vfsuid_has_fsmapping - check whether a vfsuid maps into the filesystem 1324d7ca409SChristian Brauner * @idmap: the mount's idmapping 1331e5267cdSChristian Brauner * @fs_userns: the filesystem's idmapping 1341e5267cdSChristian Brauner * @vfsuid: vfsuid to be mapped 1351e5267cdSChristian Brauner * 1361e5267cdSChristian Brauner * Check whether @vfsuid has a mapping in the filesystem idmapping. Use this 1371e5267cdSChristian Brauner * function to check whether the filesystem idmapping has a mapping for 1381e5267cdSChristian Brauner * @vfsuid. 1391e5267cdSChristian Brauner * 1401e5267cdSChristian Brauner * Return: true if @vfsuid has a mapping in the filesystem, false if not. 1411e5267cdSChristian Brauner */ 1424d7ca409SChristian Brauner static inline bool vfsuid_has_fsmapping(struct mnt_idmap *idmap, 1431e5267cdSChristian Brauner struct user_namespace *fs_userns, 1441e5267cdSChristian Brauner vfsuid_t vfsuid) 1451e5267cdSChristian Brauner { 1464d7ca409SChristian Brauner return uid_valid(from_vfsuid(idmap, fs_userns, vfsuid)); 1471e5267cdSChristian Brauner } 1481e5267cdSChristian Brauner 1499c4f28ddSChristian Brauner static inline bool vfsuid_has_mapping(struct user_namespace *userns, 1509c4f28ddSChristian Brauner vfsuid_t vfsuid) 1519c4f28ddSChristian Brauner { 1529c4f28ddSChristian Brauner return from_kuid(userns, AS_KUIDT(vfsuid)) != (uid_t)-1; 1539c4f28ddSChristian Brauner } 1549c4f28ddSChristian Brauner 1551e5267cdSChristian Brauner /** 156c9fa2b07SChristian Brauner * vfsuid_into_kuid - convert vfsuid into kuid 157c9fa2b07SChristian Brauner * @vfsuid: the vfsuid to convert 158c9fa2b07SChristian Brauner * 159c9fa2b07SChristian Brauner * This can be used when a vfsuid is committed as a kuid. 160c9fa2b07SChristian Brauner * 161c9fa2b07SChristian Brauner * Return: a kuid with the value of @vfsuid 162c9fa2b07SChristian Brauner */ 163c9fa2b07SChristian Brauner static inline kuid_t vfsuid_into_kuid(vfsuid_t vfsuid) 164c9fa2b07SChristian Brauner { 165c9fa2b07SChristian Brauner return AS_KUIDT(vfsuid); 166c9fa2b07SChristian Brauner } 167c9fa2b07SChristian Brauner 168c9fa2b07SChristian Brauner /** 1691e5267cdSChristian Brauner * vfsgid_has_fsmapping - check whether a vfsgid maps into the filesystem 1704d7ca409SChristian Brauner * @idmap: the mount's idmapping 1711e5267cdSChristian Brauner * @fs_userns: the filesystem's idmapping 1721e5267cdSChristian Brauner * @vfsgid: vfsgid to be mapped 1731e5267cdSChristian Brauner * 1741e5267cdSChristian Brauner * Check whether @vfsgid has a mapping in the filesystem idmapping. Use this 1751e5267cdSChristian Brauner * function to check whether the filesystem idmapping has a mapping for 1761e5267cdSChristian Brauner * @vfsgid. 1771e5267cdSChristian Brauner * 1781e5267cdSChristian Brauner * Return: true if @vfsgid has a mapping in the filesystem, false if not. 1791e5267cdSChristian Brauner */ 1804d7ca409SChristian Brauner static inline bool vfsgid_has_fsmapping(struct mnt_idmap *idmap, 1811e5267cdSChristian Brauner struct user_namespace *fs_userns, 1821e5267cdSChristian Brauner vfsgid_t vfsgid) 1831e5267cdSChristian Brauner { 1844d7ca409SChristian Brauner return gid_valid(from_vfsgid(idmap, fs_userns, vfsgid)); 1851ac2a410SChristian Brauner } 1861ac2a410SChristian Brauner 1879c4f28ddSChristian Brauner static inline bool vfsgid_has_mapping(struct user_namespace *userns, 1889c4f28ddSChristian Brauner vfsgid_t vfsgid) 1899c4f28ddSChristian Brauner { 1909c4f28ddSChristian Brauner return from_kgid(userns, AS_KGIDT(vfsgid)) != (gid_t)-1; 1919c4f28ddSChristian Brauner } 1929c4f28ddSChristian Brauner 1931ac2a410SChristian Brauner /** 194c9fa2b07SChristian Brauner * vfsgid_into_kgid - convert vfsgid into kgid 195c9fa2b07SChristian Brauner * @vfsgid: the vfsgid to convert 196c9fa2b07SChristian Brauner * 197c9fa2b07SChristian Brauner * This can be used when a vfsgid is committed as a kgid. 198c9fa2b07SChristian Brauner * 199c9fa2b07SChristian Brauner * Return: a kgid with the value of @vfsgid 200c9fa2b07SChristian Brauner */ 201c9fa2b07SChristian Brauner static inline kgid_t vfsgid_into_kgid(vfsgid_t vfsgid) 202c9fa2b07SChristian Brauner { 203c9fa2b07SChristian Brauner return AS_KGIDT(vfsgid); 204c9fa2b07SChristian Brauner } 205c9fa2b07SChristian Brauner 206c9fa2b07SChristian Brauner /** 207c14329d3SChristian Brauner * mapped_fsuid - return caller's fsuid mapped according to an idmapping 208c14329d3SChristian Brauner * @idmap: the mount's idmapping 209209188ceSChristian Brauner * @fs_userns: the filesystem's idmapping 210a793d79eSChristian Brauner * 211a793d79eSChristian Brauner * Use this helper to initialize a new vfs or filesystem object based on 212a793d79eSChristian Brauner * the caller's fsuid. A common example is initializing the i_uid field of 213a793d79eSChristian Brauner * a newly allocated inode triggered by a creation event such as mkdir or 214a793d79eSChristian Brauner * O_CREAT. Other examples include the allocation of quotas for a specific 215a793d79eSChristian Brauner * user. 216a793d79eSChristian Brauner * 217c14329d3SChristian Brauner * Return: the caller's current fsuid mapped up according to @idmap. 218a793d79eSChristian Brauner */ 219c14329d3SChristian Brauner static inline kuid_t mapped_fsuid(struct mnt_idmap *idmap, 220209188ceSChristian Brauner struct user_namespace *fs_userns) 221a793d79eSChristian Brauner { 2224d7ca409SChristian Brauner return from_vfsuid(idmap, fs_userns, VFSUIDT_INIT(current_fsuid())); 223a793d79eSChristian Brauner } 224a793d79eSChristian Brauner 225a793d79eSChristian Brauner /** 226c14329d3SChristian Brauner * mapped_fsgid - return caller's fsgid mapped according to an idmapping 227c14329d3SChristian Brauner * @idmap: the mount's idmapping 228209188ceSChristian Brauner * @fs_userns: the filesystem's idmapping 229a793d79eSChristian Brauner * 230a793d79eSChristian Brauner * Use this helper to initialize a new vfs or filesystem object based on 231a793d79eSChristian Brauner * the caller's fsgid. A common example is initializing the i_gid field of 232a793d79eSChristian Brauner * a newly allocated inode triggered by a creation event such as mkdir or 233a793d79eSChristian Brauner * O_CREAT. Other examples include the allocation of quotas for a specific 234a793d79eSChristian Brauner * user. 235a793d79eSChristian Brauner * 236c14329d3SChristian Brauner * Return: the caller's current fsgid mapped up according to @idmap. 237a793d79eSChristian Brauner */ 238c14329d3SChristian Brauner static inline kgid_t mapped_fsgid(struct mnt_idmap *idmap, 239209188ceSChristian Brauner struct user_namespace *fs_userns) 240a793d79eSChristian Brauner { 2414d7ca409SChristian Brauner return from_vfsgid(idmap, fs_userns, VFSGIDT_INIT(current_fsgid())); 242a793d79eSChristian Brauner } 243a793d79eSChristian Brauner 244*3707d84cSChristian Brauner bool check_fsmapping(const struct mnt_idmap *idmap, 245*3707d84cSChristian Brauner const struct super_block *sb); 246*3707d84cSChristian Brauner 247a793d79eSChristian Brauner #endif /* _LINUX_MNT_IDMAPPING_H */ 248