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 10 #include "internal.h" 11 12 struct mnt_idmap { 13 struct user_namespace *owner; 14 refcount_t count; 15 }; 16 17 /* 18 * Carries the initial idmapping of 0:0:4294967295 which is an identity 19 * mapping. This means that {g,u}id 0 is mapped to {g,u}id 0, {g,u}id 1 is 20 * mapped to {g,u}id 1, [...], {g,u}id 1000 to {g,u}id 1000, [...]. 21 */ 22 struct mnt_idmap nop_mnt_idmap = { 23 .owner = &init_user_ns, 24 .count = REFCOUNT_INIT(1), 25 }; 26 EXPORT_SYMBOL_GPL(nop_mnt_idmap); 27 28 /** 29 * check_fsmapping - check whether an mount idmapping is allowed 30 * @idmap: idmap of the relevent mount 31 * @sb: super block of the filesystem 32 * 33 * Return: true if @idmap is allowed, false if not. 34 */ 35 bool check_fsmapping(const struct mnt_idmap *idmap, 36 const struct super_block *sb) 37 { 38 return idmap->owner != sb->s_user_ns; 39 } 40 41 /** 42 * initial_idmapping - check whether this is the initial mapping 43 * @ns: idmapping to check 44 * 45 * Check whether this is the initial mapping, mapping 0 to 0, 1 to 1, 46 * [...], 1000 to 1000 [...]. 47 * 48 * Return: true if this is the initial mapping, false if not. 49 */ 50 static inline bool initial_idmapping(const struct user_namespace *ns) 51 { 52 return ns == &init_user_ns; 53 } 54 55 /** 56 * no_idmapping - check whether we can skip remapping a kuid/gid 57 * @mnt_userns: the mount's idmapping 58 * @fs_userns: the filesystem's idmapping 59 * 60 * This function can be used to check whether a remapping between two 61 * idmappings is required. 62 * An idmapped mount is a mount that has an idmapping attached to it that 63 * is different from the filsystem's idmapping and the initial idmapping. 64 * If the initial mapping is used or the idmapping of the mount and the 65 * filesystem are identical no remapping is required. 66 * 67 * Return: true if remapping can be skipped, false if not. 68 */ 69 static inline bool no_idmapping(const struct user_namespace *mnt_userns, 70 const struct user_namespace *fs_userns) 71 { 72 return initial_idmapping(mnt_userns) || mnt_userns == fs_userns; 73 } 74 75 /** 76 * make_vfsuid - map a filesystem kuid according to an idmapping 77 * @idmap: the mount's idmapping 78 * @fs_userns: the filesystem's idmapping 79 * @kuid : kuid to be mapped 80 * 81 * Take a @kuid and remap it from @fs_userns into @idmap. Use this 82 * function when preparing a @kuid to be reported to userspace. 83 * 84 * If no_idmapping() determines that this is not an idmapped mount we can 85 * simply return @kuid unchanged. 86 * If initial_idmapping() tells us that the filesystem is not mounted with an 87 * idmapping we know the value of @kuid won't change when calling 88 * from_kuid() so we can simply retrieve the value via __kuid_val() 89 * directly. 90 * 91 * Return: @kuid mapped according to @idmap. 92 * If @kuid has no mapping in either @idmap or @fs_userns INVALID_UID is 93 * returned. 94 */ 95 96 vfsuid_t make_vfsuid(struct mnt_idmap *idmap, 97 struct user_namespace *fs_userns, 98 kuid_t kuid) 99 { 100 uid_t uid; 101 struct user_namespace *mnt_userns = idmap->owner; 102 103 if (no_idmapping(mnt_userns, fs_userns)) 104 return VFSUIDT_INIT(kuid); 105 if (initial_idmapping(fs_userns)) 106 uid = __kuid_val(kuid); 107 else 108 uid = from_kuid(fs_userns, kuid); 109 if (uid == (uid_t)-1) 110 return INVALID_VFSUID; 111 return VFSUIDT_INIT(make_kuid(mnt_userns, uid)); 112 } 113 EXPORT_SYMBOL_GPL(make_vfsuid); 114 115 /** 116 * make_vfsgid - map a filesystem kgid according to an idmapping 117 * @idmap: the mount's idmapping 118 * @fs_userns: the filesystem's idmapping 119 * @kgid : kgid to be mapped 120 * 121 * Take a @kgid and remap it from @fs_userns into @idmap. Use this 122 * function when preparing a @kgid to be reported to userspace. 123 * 124 * If no_idmapping() determines that this is not an idmapped mount we can 125 * simply return @kgid unchanged. 126 * If initial_idmapping() tells us that the filesystem is not mounted with an 127 * idmapping we know the value of @kgid won't change when calling 128 * from_kgid() so we can simply retrieve the value via __kgid_val() 129 * directly. 130 * 131 * Return: @kgid mapped according to @idmap. 132 * If @kgid has no mapping in either @idmap or @fs_userns INVALID_GID is 133 * returned. 134 */ 135 vfsgid_t make_vfsgid(struct mnt_idmap *idmap, 136 struct user_namespace *fs_userns, kgid_t kgid) 137 { 138 gid_t gid; 139 struct user_namespace *mnt_userns = idmap->owner; 140 141 if (no_idmapping(mnt_userns, fs_userns)) 142 return VFSGIDT_INIT(kgid); 143 if (initial_idmapping(fs_userns)) 144 gid = __kgid_val(kgid); 145 else 146 gid = from_kgid(fs_userns, kgid); 147 if (gid == (gid_t)-1) 148 return INVALID_VFSGID; 149 return VFSGIDT_INIT(make_kgid(mnt_userns, gid)); 150 } 151 EXPORT_SYMBOL_GPL(make_vfsgid); 152 153 /** 154 * from_vfsuid - map a vfsuid into the filesystem idmapping 155 * @idmap: the mount's idmapping 156 * @fs_userns: the filesystem's idmapping 157 * @vfsuid : vfsuid to be mapped 158 * 159 * Map @vfsuid into the filesystem idmapping. This function has to be used in 160 * order to e.g. write @vfsuid to inode->i_uid. 161 * 162 * Return: @vfsuid mapped into the filesystem idmapping 163 */ 164 kuid_t from_vfsuid(struct mnt_idmap *idmap, 165 struct user_namespace *fs_userns, vfsuid_t vfsuid) 166 { 167 uid_t uid; 168 struct user_namespace *mnt_userns = idmap->owner; 169 170 if (no_idmapping(mnt_userns, fs_userns)) 171 return AS_KUIDT(vfsuid); 172 uid = from_kuid(mnt_userns, AS_KUIDT(vfsuid)); 173 if (uid == (uid_t)-1) 174 return INVALID_UID; 175 if (initial_idmapping(fs_userns)) 176 return KUIDT_INIT(uid); 177 return make_kuid(fs_userns, uid); 178 } 179 EXPORT_SYMBOL_GPL(from_vfsuid); 180 181 /** 182 * from_vfsgid - map a vfsgid into the filesystem idmapping 183 * @idmap: the mount's idmapping 184 * @fs_userns: the filesystem's idmapping 185 * @vfsgid : vfsgid to be mapped 186 * 187 * Map @vfsgid into the filesystem idmapping. This function has to be used in 188 * order to e.g. write @vfsgid to inode->i_gid. 189 * 190 * Return: @vfsgid mapped into the filesystem idmapping 191 */ 192 kgid_t from_vfsgid(struct mnt_idmap *idmap, 193 struct user_namespace *fs_userns, vfsgid_t vfsgid) 194 { 195 gid_t gid; 196 struct user_namespace *mnt_userns = idmap->owner; 197 198 if (no_idmapping(mnt_userns, fs_userns)) 199 return AS_KGIDT(vfsgid); 200 gid = from_kgid(mnt_userns, AS_KGIDT(vfsgid)); 201 if (gid == (gid_t)-1) 202 return INVALID_GID; 203 if (initial_idmapping(fs_userns)) 204 return KGIDT_INIT(gid); 205 return make_kgid(fs_userns, gid); 206 } 207 EXPORT_SYMBOL_GPL(from_vfsgid); 208 209 #ifdef CONFIG_MULTIUSER 210 /** 211 * vfsgid_in_group_p() - check whether a vfsuid matches the caller's groups 212 * @vfsgid: the mnt gid to match 213 * 214 * This function can be used to determine whether @vfsuid matches any of the 215 * caller's groups. 216 * 217 * Return: 1 if vfsuid matches caller's groups, 0 if not. 218 */ 219 int vfsgid_in_group_p(vfsgid_t vfsgid) 220 { 221 return in_group_p(AS_KGIDT(vfsgid)); 222 } 223 #else 224 int vfsgid_in_group_p(vfsgid_t vfsgid) 225 { 226 return 1; 227 } 228 #endif 229 EXPORT_SYMBOL_GPL(vfsgid_in_group_p); 230 231 struct mnt_idmap *alloc_mnt_idmap(struct user_namespace *mnt_userns) 232 { 233 struct mnt_idmap *idmap; 234 235 idmap = kzalloc(sizeof(struct mnt_idmap), GFP_KERNEL_ACCOUNT); 236 if (!idmap) 237 return ERR_PTR(-ENOMEM); 238 239 idmap->owner = get_user_ns(mnt_userns); 240 refcount_set(&idmap->count, 1); 241 return idmap; 242 } 243 244 /** 245 * mnt_idmap_get - get a reference to an idmapping 246 * @idmap: the idmap to bump the reference on 247 * 248 * If @idmap is not the @nop_mnt_idmap bump the reference count. 249 * 250 * Return: @idmap with reference count bumped if @not_mnt_idmap isn't passed. 251 */ 252 struct mnt_idmap *mnt_idmap_get(struct mnt_idmap *idmap) 253 { 254 if (idmap != &nop_mnt_idmap) 255 refcount_inc(&idmap->count); 256 257 return idmap; 258 } 259 260 /** 261 * mnt_idmap_put - put a reference to an idmapping 262 * @idmap: the idmap to put the reference on 263 * 264 * If this is a non-initial idmapping, put the reference count when a mount is 265 * released and free it if we're the last user. 266 */ 267 void mnt_idmap_put(struct mnt_idmap *idmap) 268 { 269 if (idmap != &nop_mnt_idmap && refcount_dec_and_test(&idmap->count)) { 270 put_user_ns(idmap->owner); 271 kfree(idmap); 272 } 273 } 274