Line data Source code
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 1254 : bool check_fsmapping(const struct mnt_idmap *idmap, 36 : const struct super_block *sb) 37 : { 38 1254 : 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 >38263*10^7 : 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 32190086 : 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 >22526*10^7 : vfsuid_t make_vfsuid(struct mnt_idmap *idmap, 97 : struct user_namespace *fs_userns, 98 : kuid_t kuid) 99 : { 100 >22526*10^7 : uid_t uid; 101 >22526*10^7 : struct user_namespace *mnt_userns = idmap->owner; 102 : 103 >22527*10^7 : if (no_idmapping(mnt_userns, fs_userns)) 104 >22524*10^7 : return VFSUIDT_INIT(kuid); 105 19442218 : if (initial_idmapping(fs_userns)) 106 19442218 : uid = __kuid_val(kuid); 107 : else 108 0 : uid = from_kuid(fs_userns, kuid); 109 19442218 : if (uid == (uid_t)-1) 110 80 : return INVALID_VFSUID; 111 19442138 : 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 >15440*10^7 : vfsgid_t make_vfsgid(struct mnt_idmap *idmap, 136 : struct user_namespace *fs_userns, kgid_t kgid) 137 : { 138 >15440*10^7 : gid_t gid; 139 >15440*10^7 : struct user_namespace *mnt_userns = idmap->owner; 140 : 141 >15441*10^7 : if (no_idmapping(mnt_userns, fs_userns)) 142 >15439*10^7 : return VFSGIDT_INIT(kgid); 143 7335463 : if (initial_idmapping(fs_userns)) 144 7335463 : gid = __kgid_val(kgid); 145 : else 146 0 : gid = from_kgid(fs_userns, kgid); 147 7335463 : if (gid == (gid_t)-1) 148 0 : return INVALID_VFSGID; 149 7335463 : 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 1470287160 : kuid_t from_vfsuid(struct mnt_idmap *idmap, 165 : struct user_namespace *fs_userns, vfsuid_t vfsuid) 166 : { 167 1470287160 : uid_t uid; 168 1470287160 : struct user_namespace *mnt_userns = idmap->owner; 169 : 170 1472993910 : if (no_idmapping(mnt_userns, fs_userns)) 171 1467580410 : return AS_KUIDT(vfsuid); 172 2706750 : uid = from_kuid(mnt_userns, AS_KUIDT(vfsuid)); 173 2706750 : if (uid == (uid_t)-1) 174 689 : return INVALID_UID; 175 2706061 : if (initial_idmapping(fs_userns)) 176 2706061 : return KUIDT_INIT(uid); 177 0 : 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 1470027052 : kgid_t from_vfsgid(struct mnt_idmap *idmap, 193 : struct user_namespace *fs_userns, vfsgid_t vfsgid) 194 : { 195 1470027052 : gid_t gid; 196 1470027052 : struct user_namespace *mnt_userns = idmap->owner; 197 : 198 1472732707 : if (no_idmapping(mnt_userns, fs_userns)) 199 1467321397 : return AS_KGIDT(vfsgid); 200 2705655 : gid = from_kgid(mnt_userns, AS_KGIDT(vfsgid)); 201 2705655 : if (gid == (gid_t)-1) 202 261 : return INVALID_GID; 203 2705394 : if (initial_idmapping(fs_userns)) 204 2705394 : return KGIDT_INIT(gid); 205 0 : 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 40804936 : int vfsgid_in_group_p(vfsgid_t vfsgid) 220 : { 221 40804936 : 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 1254 : struct mnt_idmap *alloc_mnt_idmap(struct user_namespace *mnt_userns) 232 : { 233 1254 : struct mnt_idmap *idmap; 234 : 235 1254 : idmap = kzalloc(sizeof(struct mnt_idmap), GFP_KERNEL_ACCOUNT); 236 1254 : if (!idmap) 237 : return ERR_PTR(-ENOMEM); 238 : 239 1254 : idmap->owner = get_user_ns(mnt_userns); 240 1254 : refcount_set(&idmap->count, 1); 241 1254 : 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 3092339 : struct mnt_idmap *mnt_idmap_get(struct mnt_idmap *idmap) 253 : { 254 3092339 : if (idmap != &nop_mnt_idmap) 255 6117 : refcount_inc(&idmap->count); 256 : 257 3092339 : 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 3216110 : void mnt_idmap_put(struct mnt_idmap *idmap) 268 : { 269 3216110 : if (idmap != &nop_mnt_idmap && refcount_dec_and_test(&idmap->count)) { 270 1254 : put_user_ns(idmap->owner); 271 1254 : kfree(idmap); 272 : } 273 3216111 : }