xref: /linux-6.15/include/linux/mnt_idmapping.h (revision eb7718cd)
1 /* SPDX-License-Identifier: GPL-2.0 */
2 #ifndef _LINUX_MNT_IDMAPPING_H
3 #define _LINUX_MNT_IDMAPPING_H
4 
5 #include <linux/types.h>
6 #include <linux/uidgid.h>
7 
8 struct user_namespace;
9 /*
10  * Carries the initial idmapping of 0:0:4294967295 which is an identity
11  * mapping. This means that {g,u}id 0 is mapped to {g,u}id 0, {g,u}id 1 is
12  * mapped to {g,u}id 1, [...], {g,u}id 1000 to {g,u}id 1000, [...].
13  */
14 extern struct user_namespace init_user_ns;
15 
16 typedef struct {
17 	uid_t val;
18 } vfsuid_t;
19 
20 typedef struct {
21 	gid_t val;
22 } vfsgid_t;
23 
24 static_assert(sizeof(vfsuid_t) == sizeof(kuid_t));
25 static_assert(sizeof(vfsgid_t) == sizeof(kgid_t));
26 static_assert(offsetof(vfsuid_t, val) == offsetof(kuid_t, val));
27 static_assert(offsetof(vfsgid_t, val) == offsetof(kgid_t, val));
28 
29 #ifdef CONFIG_MULTIUSER
30 static inline uid_t __vfsuid_val(vfsuid_t uid)
31 {
32 	return uid.val;
33 }
34 
35 static inline gid_t __vfsgid_val(vfsgid_t gid)
36 {
37 	return gid.val;
38 }
39 #else
40 static inline uid_t __vfsuid_val(vfsuid_t uid)
41 {
42 	return 0;
43 }
44 
45 static inline gid_t __vfsgid_val(vfsgid_t gid)
46 {
47 	return 0;
48 }
49 #endif
50 
51 static inline bool vfsuid_valid(vfsuid_t uid)
52 {
53 	return __vfsuid_val(uid) != (uid_t)-1;
54 }
55 
56 static inline bool vfsgid_valid(vfsgid_t gid)
57 {
58 	return __vfsgid_val(gid) != (gid_t)-1;
59 }
60 
61 static inline bool vfsuid_eq(vfsuid_t left, vfsuid_t right)
62 {
63 	return vfsuid_valid(left) && __vfsuid_val(left) == __vfsuid_val(right);
64 }
65 
66 static inline bool vfsgid_eq(vfsgid_t left, vfsgid_t right)
67 {
68 	return vfsgid_valid(left) && __vfsgid_val(left) == __vfsgid_val(right);
69 }
70 
71 /**
72  * vfsuid_eq_kuid - check whether kuid and vfsuid have the same value
73  * @vfsuid: the vfsuid to compare
74  * @kuid: the kuid to compare
75  *
76  * Check whether @vfsuid and @kuid have the same values.
77  *
78  * Return: true if @vfsuid and @kuid have the same value, false if not.
79  * Comparison between two invalid uids returns false.
80  */
81 static inline bool vfsuid_eq_kuid(vfsuid_t vfsuid, kuid_t kuid)
82 {
83 	return vfsuid_valid(vfsuid) && __vfsuid_val(vfsuid) == __kuid_val(kuid);
84 }
85 
86 /**
87  * vfsgid_eq_kgid - check whether kgid and vfsgid have the same value
88  * @vfsgid: the vfsgid to compare
89  * @kgid: the kgid to compare
90  *
91  * Check whether @vfsgid and @kgid have the same values.
92  *
93  * Return: true if @vfsgid and @kgid have the same value, false if not.
94  * Comparison between two invalid gids returns false.
95  */
96 static inline bool vfsgid_eq_kgid(vfsgid_t vfsgid, kgid_t kgid)
97 {
98 	return vfsgid_valid(vfsgid) && __vfsgid_val(vfsgid) == __kgid_val(kgid);
99 }
100 
101 static inline bool vfsuid_gt_kuid(vfsuid_t vfsuid, kuid_t kuid)
102 {
103 	return __vfsuid_val(vfsuid) > __kuid_val(kuid);
104 }
105 
106 static inline bool vfsgid_gt_kgid(vfsgid_t vfsgid, kgid_t kgid)
107 {
108 	return __vfsgid_val(vfsgid) > __kgid_val(kgid);
109 }
110 
111 static inline bool vfsuid_lt_kuid(vfsuid_t vfsuid, kuid_t kuid)
112 {
113 	return __vfsuid_val(vfsuid) < __kuid_val(kuid);
114 }
115 
116 static inline bool vfsgid_lt_kgid(vfsgid_t vfsgid, kgid_t kgid)
117 {
118 	return __vfsgid_val(vfsgid) < __kgid_val(kgid);
119 }
120 
121 /*
122  * vfs{g,u}ids are created from k{g,u}ids.
123  * We don't allow them to be created from regular {u,g}id.
124  */
125 #define VFSUIDT_INIT(val) (vfsuid_t){ __kuid_val(val) }
126 #define VFSGIDT_INIT(val) (vfsgid_t){ __kgid_val(val) }
127 
128 #define INVALID_VFSUID VFSUIDT_INIT(INVALID_UID)
129 #define INVALID_VFSGID VFSGIDT_INIT(INVALID_GID)
130 
131 /*
132  * Allow a vfs{g,u}id to be used as a k{g,u}id where we want to compare
133  * whether the mapped value is identical to value of a k{g,u}id.
134  */
135 #define AS_KUIDT(val) (kuid_t){ __vfsuid_val(val) }
136 #define AS_KGIDT(val) (kgid_t){ __vfsgid_val(val) }
137 
138 #ifdef CONFIG_MULTIUSER
139 /**
140  * vfsgid_in_group_p() - check whether a vfsuid matches the caller's groups
141  * @vfsgid: the mnt gid to match
142  *
143  * This function can be used to determine whether @vfsuid matches any of the
144  * caller's groups.
145  *
146  * Return: 1 if vfsuid matches caller's groups, 0 if not.
147  */
148 static inline int vfsgid_in_group_p(vfsgid_t vfsgid)
149 {
150 	return in_group_p(AS_KGIDT(vfsgid));
151 }
152 #else
153 static inline int vfsgid_in_group_p(vfsgid_t vfsgid)
154 {
155 	return 1;
156 }
157 #endif
158 
159 /**
160  * initial_idmapping - check whether this is the initial mapping
161  * @ns: idmapping to check
162  *
163  * Check whether this is the initial mapping, mapping 0 to 0, 1 to 1,
164  * [...], 1000 to 1000 [...].
165  *
166  * Return: true if this is the initial mapping, false if not.
167  */
168 static inline bool initial_idmapping(const struct user_namespace *ns)
169 {
170 	return ns == &init_user_ns;
171 }
172 
173 /**
174  * no_idmapping - check whether we can skip remapping a kuid/gid
175  * @mnt_userns: the mount's idmapping
176  * @fs_userns: the filesystem's idmapping
177  *
178  * This function can be used to check whether a remapping between two
179  * idmappings is required.
180  * An idmapped mount is a mount that has an idmapping attached to it that
181  * is different from the filsystem's idmapping and the initial idmapping.
182  * If the initial mapping is used or the idmapping of the mount and the
183  * filesystem are identical no remapping is required.
184  *
185  * Return: true if remapping can be skipped, false if not.
186  */
187 static inline bool no_idmapping(const struct user_namespace *mnt_userns,
188 				const struct user_namespace *fs_userns)
189 {
190 	return initial_idmapping(mnt_userns) || mnt_userns == fs_userns;
191 }
192 
193 /**
194  * make_vfsuid - map a filesystem kuid into a mnt_userns
195  * @mnt_userns: the mount's idmapping
196  * @fs_userns: the filesystem's idmapping
197  * @kuid : kuid to be mapped
198  *
199  * Take a @kuid and remap it from @fs_userns into @mnt_userns. Use this
200  * function when preparing a @kuid to be reported to userspace.
201  *
202  * If no_idmapping() determines that this is not an idmapped mount we can
203  * simply return @kuid unchanged.
204  * If initial_idmapping() tells us that the filesystem is not mounted with an
205  * idmapping we know the value of @kuid won't change when calling
206  * from_kuid() so we can simply retrieve the value via __kuid_val()
207  * directly.
208  *
209  * Return: @kuid mapped according to @mnt_userns.
210  * If @kuid has no mapping in either @mnt_userns or @fs_userns INVALID_UID is
211  * returned.
212  */
213 
214 static inline vfsuid_t make_vfsuid(struct user_namespace *mnt_userns,
215 				   struct user_namespace *fs_userns,
216 				   kuid_t kuid)
217 {
218 	uid_t uid;
219 
220 	if (no_idmapping(mnt_userns, fs_userns))
221 		return VFSUIDT_INIT(kuid);
222 	if (initial_idmapping(fs_userns))
223 		uid = __kuid_val(kuid);
224 	else
225 		uid = from_kuid(fs_userns, kuid);
226 	if (uid == (uid_t)-1)
227 		return INVALID_VFSUID;
228 	return VFSUIDT_INIT(make_kuid(mnt_userns, uid));
229 }
230 
231 /**
232  * make_vfsgid - map a filesystem kgid into a mnt_userns
233  * @mnt_userns: the mount's idmapping
234  * @fs_userns: the filesystem's idmapping
235  * @kgid : kgid to be mapped
236  *
237  * Take a @kgid and remap it from @fs_userns into @mnt_userns. Use this
238  * function when preparing a @kgid to be reported to userspace.
239  *
240  * If no_idmapping() determines that this is not an idmapped mount we can
241  * simply return @kgid unchanged.
242  * If initial_idmapping() tells us that the filesystem is not mounted with an
243  * idmapping we know the value of @kgid won't change when calling
244  * from_kgid() so we can simply retrieve the value via __kgid_val()
245  * directly.
246  *
247  * Return: @kgid mapped according to @mnt_userns.
248  * If @kgid has no mapping in either @mnt_userns or @fs_userns INVALID_GID is
249  * returned.
250  */
251 
252 static inline vfsgid_t make_vfsgid(struct user_namespace *mnt_userns,
253 				   struct user_namespace *fs_userns,
254 				   kgid_t kgid)
255 {
256 	gid_t gid;
257 
258 	if (no_idmapping(mnt_userns, fs_userns))
259 		return VFSGIDT_INIT(kgid);
260 	if (initial_idmapping(fs_userns))
261 		gid = __kgid_val(kgid);
262 	else
263 		gid = from_kgid(fs_userns, kgid);
264 	if (gid == (gid_t)-1)
265 		return INVALID_VFSGID;
266 	return VFSGIDT_INIT(make_kgid(mnt_userns, gid));
267 }
268 
269 /**
270  * from_vfsuid - map a vfsuid into the filesystem idmapping
271  * @mnt_userns: the mount's idmapping
272  * @fs_userns: the filesystem's idmapping
273  * @vfsuid : vfsuid to be mapped
274  *
275  * Map @vfsuid into the filesystem idmapping. This function has to be used in
276  * order to e.g. write @vfsuid to inode->i_uid.
277  *
278  * Return: @vfsuid mapped into the filesystem idmapping
279  */
280 static inline kuid_t from_vfsuid(struct user_namespace *mnt_userns,
281 				 struct user_namespace *fs_userns,
282 				 vfsuid_t vfsuid)
283 {
284 	uid_t uid;
285 
286 	if (no_idmapping(mnt_userns, fs_userns))
287 		return AS_KUIDT(vfsuid);
288 	uid = from_kuid(mnt_userns, AS_KUIDT(vfsuid));
289 	if (uid == (uid_t)-1)
290 		return INVALID_UID;
291 	if (initial_idmapping(fs_userns))
292 		return KUIDT_INIT(uid);
293 	return make_kuid(fs_userns, uid);
294 }
295 
296 /**
297  * vfsuid_has_fsmapping - check whether a vfsuid maps into the filesystem
298  * @mnt_userns: the mount's idmapping
299  * @fs_userns: the filesystem's idmapping
300  * @vfsuid: vfsuid to be mapped
301  *
302  * Check whether @vfsuid has a mapping in the filesystem idmapping. Use this
303  * function to check whether the filesystem idmapping has a mapping for
304  * @vfsuid.
305  *
306  * Return: true if @vfsuid has a mapping in the filesystem, false if not.
307  */
308 static inline bool vfsuid_has_fsmapping(struct user_namespace *mnt_userns,
309 					struct user_namespace *fs_userns,
310 					vfsuid_t vfsuid)
311 {
312 	return uid_valid(from_vfsuid(mnt_userns, fs_userns, vfsuid));
313 }
314 
315 static inline bool vfsuid_has_mapping(struct user_namespace *userns,
316 				      vfsuid_t vfsuid)
317 {
318 	return from_kuid(userns, AS_KUIDT(vfsuid)) != (uid_t)-1;
319 }
320 
321 /**
322  * vfsuid_into_kuid - convert vfsuid into kuid
323  * @vfsuid: the vfsuid to convert
324  *
325  * This can be used when a vfsuid is committed as a kuid.
326  *
327  * Return: a kuid with the value of @vfsuid
328  */
329 static inline kuid_t vfsuid_into_kuid(vfsuid_t vfsuid)
330 {
331 	return AS_KUIDT(vfsuid);
332 }
333 
334 /**
335  * from_vfsgid - map a vfsgid into the filesystem idmapping
336  * @mnt_userns: the mount's idmapping
337  * @fs_userns: the filesystem's idmapping
338  * @vfsgid : vfsgid to be mapped
339  *
340  * Map @vfsgid into the filesystem idmapping. This function has to be used in
341  * order to e.g. write @vfsgid to inode->i_gid.
342  *
343  * Return: @vfsgid mapped into the filesystem idmapping
344  */
345 static inline kgid_t from_vfsgid(struct user_namespace *mnt_userns,
346 				 struct user_namespace *fs_userns,
347 				 vfsgid_t vfsgid)
348 {
349 	gid_t gid;
350 
351 	if (no_idmapping(mnt_userns, fs_userns))
352 		return AS_KGIDT(vfsgid);
353 	gid = from_kgid(mnt_userns, AS_KGIDT(vfsgid));
354 	if (gid == (gid_t)-1)
355 		return INVALID_GID;
356 	if (initial_idmapping(fs_userns))
357 		return KGIDT_INIT(gid);
358 	return make_kgid(fs_userns, gid);
359 }
360 
361 /**
362  * vfsgid_has_fsmapping - check whether a vfsgid maps into the filesystem
363  * @mnt_userns: the mount's idmapping
364  * @fs_userns: the filesystem's idmapping
365  * @vfsgid: vfsgid to be mapped
366  *
367  * Check whether @vfsgid has a mapping in the filesystem idmapping. Use this
368  * function to check whether the filesystem idmapping has a mapping for
369  * @vfsgid.
370  *
371  * Return: true if @vfsgid has a mapping in the filesystem, false if not.
372  */
373 static inline bool vfsgid_has_fsmapping(struct user_namespace *mnt_userns,
374 					struct user_namespace *fs_userns,
375 					vfsgid_t vfsgid)
376 {
377 	return gid_valid(from_vfsgid(mnt_userns, fs_userns, vfsgid));
378 }
379 
380 static inline bool vfsgid_has_mapping(struct user_namespace *userns,
381 				      vfsgid_t vfsgid)
382 {
383 	return from_kgid(userns, AS_KGIDT(vfsgid)) != (gid_t)-1;
384 }
385 
386 /**
387  * vfsgid_into_kgid - convert vfsgid into kgid
388  * @vfsgid: the vfsgid to convert
389  *
390  * This can be used when a vfsgid is committed as a kgid.
391  *
392  * Return: a kgid with the value of @vfsgid
393  */
394 static inline kgid_t vfsgid_into_kgid(vfsgid_t vfsgid)
395 {
396 	return AS_KGIDT(vfsgid);
397 }
398 
399 /**
400  * mapped_fsuid - return caller's fsuid mapped up into a mnt_userns
401  * @mnt_userns: the mount's idmapping
402  * @fs_userns: the filesystem's idmapping
403  *
404  * Use this helper to initialize a new vfs or filesystem object based on
405  * the caller's fsuid. A common example is initializing the i_uid field of
406  * a newly allocated inode triggered by a creation event such as mkdir or
407  * O_CREAT. Other examples include the allocation of quotas for a specific
408  * user.
409  *
410  * Return: the caller's current fsuid mapped up according to @mnt_userns.
411  */
412 static inline kuid_t mapped_fsuid(struct user_namespace *mnt_userns,
413 				  struct user_namespace *fs_userns)
414 {
415 	return from_vfsuid(mnt_userns, fs_userns,
416 			   VFSUIDT_INIT(current_fsuid()));
417 }
418 
419 /**
420  * mapped_fsgid - return caller's fsgid mapped up into a mnt_userns
421  * @mnt_userns: the mount's idmapping
422  * @fs_userns: the filesystem's idmapping
423  *
424  * Use this helper to initialize a new vfs or filesystem object based on
425  * the caller's fsgid. A common example is initializing the i_gid field of
426  * a newly allocated inode triggered by a creation event such as mkdir or
427  * O_CREAT. Other examples include the allocation of quotas for a specific
428  * user.
429  *
430  * Return: the caller's current fsgid mapped up according to @mnt_userns.
431  */
432 static inline kgid_t mapped_fsgid(struct user_namespace *mnt_userns,
433 				  struct user_namespace *fs_userns)
434 {
435 	return from_vfsgid(mnt_userns, fs_userns,
436 			   VFSGIDT_INIT(current_fsgid()));
437 }
438 
439 #endif /* _LINUX_MNT_IDMAPPING_H */
440