mnt_idmapping: add missing helpers
[linux-2.6-microblaze.git] / include / linux / mnt_idmapping.h
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 static inline kuid_t mapped_kuid_fs(struct user_namespace *mnt_userns,
232                                     struct user_namespace *fs_userns,
233                                     kuid_t kuid)
234 {
235         return AS_KUIDT(make_vfsuid(mnt_userns, fs_userns, kuid));
236 }
237
238 /**
239  * make_vfsgid - map a filesystem kgid into a mnt_userns
240  * @mnt_userns: the mount's idmapping
241  * @fs_userns: the filesystem's idmapping
242  * @kgid : kgid to be mapped
243  *
244  * Take a @kgid and remap it from @fs_userns into @mnt_userns. Use this
245  * function when preparing a @kgid to be reported to userspace.
246  *
247  * If no_idmapping() determines that this is not an idmapped mount we can
248  * simply return @kgid unchanged.
249  * If initial_idmapping() tells us that the filesystem is not mounted with an
250  * idmapping we know the value of @kgid won't change when calling
251  * from_kgid() so we can simply retrieve the value via __kgid_val()
252  * directly.
253  *
254  * Return: @kgid mapped according to @mnt_userns.
255  * If @kgid has no mapping in either @mnt_userns or @fs_userns INVALID_GID is
256  * returned.
257  */
258
259 static inline vfsgid_t make_vfsgid(struct user_namespace *mnt_userns,
260                                    struct user_namespace *fs_userns,
261                                    kgid_t kgid)
262 {
263         gid_t gid;
264
265         if (no_idmapping(mnt_userns, fs_userns))
266                 return VFSGIDT_INIT(kgid);
267         if (initial_idmapping(fs_userns))
268                 gid = __kgid_val(kgid);
269         else
270                 gid = from_kgid(fs_userns, kgid);
271         if (gid == (gid_t)-1)
272                 return INVALID_VFSGID;
273         return VFSGIDT_INIT(make_kgid(mnt_userns, gid));
274 }
275
276 static inline kgid_t mapped_kgid_fs(struct user_namespace *mnt_userns,
277                                     struct user_namespace *fs_userns,
278                                     kgid_t kgid)
279 {
280         return AS_KGIDT(make_vfsgid(mnt_userns, fs_userns, kgid));
281 }
282
283 /**
284  * from_vfsuid - map a vfsuid into the filesystem idmapping
285  * @mnt_userns: the mount's idmapping
286  * @fs_userns: the filesystem's idmapping
287  * @vfsuid : vfsuid to be mapped
288  *
289  * Map @vfsuid into the filesystem idmapping. This function has to be used in
290  * order to e.g. write @vfsuid to inode->i_uid.
291  *
292  * Return: @vfsuid mapped into the filesystem idmapping
293  */
294 static inline kuid_t from_vfsuid(struct user_namespace *mnt_userns,
295                                  struct user_namespace *fs_userns,
296                                  vfsuid_t vfsuid)
297 {
298         uid_t uid;
299
300         if (no_idmapping(mnt_userns, fs_userns))
301                 return AS_KUIDT(vfsuid);
302         uid = from_kuid(mnt_userns, AS_KUIDT(vfsuid));
303         if (uid == (uid_t)-1)
304                 return INVALID_UID;
305         if (initial_idmapping(fs_userns))
306                 return KUIDT_INIT(uid);
307         return make_kuid(fs_userns, uid);
308 }
309
310 /**
311  * mapped_kuid_user - map a user kuid into a mnt_userns
312  * @mnt_userns: the mount's idmapping
313  * @fs_userns: the filesystem's idmapping
314  * @kuid : kuid to be mapped
315  *
316  * Use the idmapping of @mnt_userns to remap a @kuid into @fs_userns. Use this
317  * function when preparing a @kuid to be written to disk or inode.
318  *
319  * If no_idmapping() determines that this is not an idmapped mount we can
320  * simply return @kuid unchanged.
321  * If initial_idmapping() tells us that the filesystem is not mounted with an
322  * idmapping we know the value of @kuid won't change when calling
323  * make_kuid() so we can simply retrieve the value via KUIDT_INIT()
324  * directly.
325  *
326  * Return: @kuid mapped according to @mnt_userns.
327  * If @kuid has no mapping in either @mnt_userns or @fs_userns INVALID_UID is
328  * returned.
329  */
330 static inline kuid_t mapped_kuid_user(struct user_namespace *mnt_userns,
331                                       struct user_namespace *fs_userns,
332                                       kuid_t kuid)
333 {
334         return from_vfsuid(mnt_userns, fs_userns, VFSUIDT_INIT(kuid));
335 }
336
337 /**
338  * vfsuid_has_fsmapping - check whether a vfsuid maps into the filesystem
339  * @mnt_userns: the mount's idmapping
340  * @fs_userns: the filesystem's idmapping
341  * @vfsuid: vfsuid to be mapped
342  *
343  * Check whether @vfsuid has a mapping in the filesystem idmapping. Use this
344  * function to check whether the filesystem idmapping has a mapping for
345  * @vfsuid.
346  *
347  * Return: true if @vfsuid has a mapping in the filesystem, false if not.
348  */
349 static inline bool vfsuid_has_fsmapping(struct user_namespace *mnt_userns,
350                                         struct user_namespace *fs_userns,
351                                         vfsuid_t vfsuid)
352 {
353         return uid_valid(from_vfsuid(mnt_userns, fs_userns, vfsuid));
354 }
355
356 static inline bool vfsuid_has_mapping(struct user_namespace *userns,
357                                       vfsuid_t vfsuid)
358 {
359         return from_kuid(userns, AS_KUIDT(vfsuid)) != (uid_t)-1;
360 }
361
362 /**
363  * vfsuid_into_kuid - convert vfsuid into kuid
364  * @vfsuid: the vfsuid to convert
365  *
366  * This can be used when a vfsuid is committed as a kuid.
367  *
368  * Return: a kuid with the value of @vfsuid
369  */
370 static inline kuid_t vfsuid_into_kuid(vfsuid_t vfsuid)
371 {
372         return AS_KUIDT(vfsuid);
373 }
374
375 /**
376  * from_vfsgid - map a vfsgid into the filesystem idmapping
377  * @mnt_userns: the mount's idmapping
378  * @fs_userns: the filesystem's idmapping
379  * @vfsgid : vfsgid to be mapped
380  *
381  * Map @vfsgid into the filesystem idmapping. This function has to be used in
382  * order to e.g. write @vfsgid to inode->i_gid.
383  *
384  * Return: @vfsgid mapped into the filesystem idmapping
385  */
386 static inline kgid_t from_vfsgid(struct user_namespace *mnt_userns,
387                                  struct user_namespace *fs_userns,
388                                  vfsgid_t vfsgid)
389 {
390         gid_t gid;
391
392         if (no_idmapping(mnt_userns, fs_userns))
393                 return AS_KGIDT(vfsgid);
394         gid = from_kgid(mnt_userns, AS_KGIDT(vfsgid));
395         if (gid == (gid_t)-1)
396                 return INVALID_GID;
397         if (initial_idmapping(fs_userns))
398                 return KGIDT_INIT(gid);
399         return make_kgid(fs_userns, gid);
400 }
401
402 /**
403  * mapped_kgid_user - map a user kgid into a mnt_userns
404  * @mnt_userns: the mount's idmapping
405  * @fs_userns: the filesystem's idmapping
406  * @kgid : kgid to be mapped
407  *
408  * Use the idmapping of @mnt_userns to remap a @kgid into @fs_userns. Use this
409  * function when preparing a @kgid to be written to disk or inode.
410  *
411  * If no_idmapping() determines that this is not an idmapped mount we can
412  * simply return @kgid unchanged.
413  * If initial_idmapping() tells us that the filesystem is not mounted with an
414  * idmapping we know the value of @kgid won't change when calling
415  * make_kgid() so we can simply retrieve the value via KGIDT_INIT()
416  * directly.
417  *
418  * Return: @kgid mapped according to @mnt_userns.
419  * If @kgid has no mapping in either @mnt_userns or @fs_userns INVALID_GID is
420  * returned.
421  */
422 static inline kgid_t mapped_kgid_user(struct user_namespace *mnt_userns,
423                                       struct user_namespace *fs_userns,
424                                       kgid_t kgid)
425 {
426         return from_vfsgid(mnt_userns, fs_userns, VFSGIDT_INIT(kgid));
427 }
428
429 /**
430  * vfsgid_has_fsmapping - check whether a vfsgid maps into the filesystem
431  * @mnt_userns: the mount's idmapping
432  * @fs_userns: the filesystem's idmapping
433  * @vfsgid: vfsgid to be mapped
434  *
435  * Check whether @vfsgid has a mapping in the filesystem idmapping. Use this
436  * function to check whether the filesystem idmapping has a mapping for
437  * @vfsgid.
438  *
439  * Return: true if @vfsgid has a mapping in the filesystem, false if not.
440  */
441 static inline bool vfsgid_has_fsmapping(struct user_namespace *mnt_userns,
442                                         struct user_namespace *fs_userns,
443                                         vfsgid_t vfsgid)
444 {
445         return gid_valid(from_vfsgid(mnt_userns, fs_userns, vfsgid));
446 }
447
448 static inline bool vfsgid_has_mapping(struct user_namespace *userns,
449                                       vfsgid_t vfsgid)
450 {
451         return from_kgid(userns, AS_KGIDT(vfsgid)) != (gid_t)-1;
452 }
453
454 /**
455  * vfsgid_into_kgid - convert vfsgid into kgid
456  * @vfsgid: the vfsgid to convert
457  *
458  * This can be used when a vfsgid is committed as a kgid.
459  *
460  * Return: a kgid with the value of @vfsgid
461  */
462 static inline kgid_t vfsgid_into_kgid(vfsgid_t vfsgid)
463 {
464         return AS_KGIDT(vfsgid);
465 }
466
467 /**
468  * mapped_fsuid - return caller's fsuid mapped up into a mnt_userns
469  * @mnt_userns: the mount's idmapping
470  * @fs_userns: the filesystem's idmapping
471  *
472  * Use this helper to initialize a new vfs or filesystem object based on
473  * the caller's fsuid. A common example is initializing the i_uid field of
474  * a newly allocated inode triggered by a creation event such as mkdir or
475  * O_CREAT. Other examples include the allocation of quotas for a specific
476  * user.
477  *
478  * Return: the caller's current fsuid mapped up according to @mnt_userns.
479  */
480 static inline kuid_t mapped_fsuid(struct user_namespace *mnt_userns,
481                                   struct user_namespace *fs_userns)
482 {
483         return from_vfsuid(mnt_userns, fs_userns,
484                            VFSUIDT_INIT(current_fsuid()));
485 }
486
487 /**
488  * mapped_fsgid - return caller's fsgid mapped up into a mnt_userns
489  * @mnt_userns: the mount's idmapping
490  * @fs_userns: the filesystem's idmapping
491  *
492  * Use this helper to initialize a new vfs or filesystem object based on
493  * the caller's fsgid. A common example is initializing the i_gid field of
494  * a newly allocated inode triggered by a creation event such as mkdir or
495  * O_CREAT. Other examples include the allocation of quotas for a specific
496  * user.
497  *
498  * Return: the caller's current fsgid mapped up according to @mnt_userns.
499  */
500 static inline kgid_t mapped_fsgid(struct user_namespace *mnt_userns,
501                                   struct user_namespace *fs_userns)
502 {
503         return from_vfsgid(mnt_userns, fs_userns,
504                            VFSGIDT_INIT(current_fsgid()));
505 }
506
507 #endif /* _LINUX_MNT_IDMAPPING_H */