xref: /openbmc/linux/include/linux/mnt_idmapping.h (revision 1ac2a4104968e0a60b4b3572216a92aab5c1b025)
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 
8a793d79eSChristian Brauner struct user_namespace;
9*1ac2a410SChristian Brauner /*
10*1ac2a410SChristian Brauner  * Carries the initial idmapping of 0:0:4294967295 which is an identity
11*1ac2a410SChristian Brauner  * mapping. This means that {g,u}id 0 is mapped to {g,u}id 0, {g,u}id 1 is
12*1ac2a410SChristian Brauner  * mapped to {g,u}id 1, [...], {g,u}id 1000 to {g,u}id 1000, [...].
13*1ac2a410SChristian Brauner  */
14a793d79eSChristian Brauner extern struct user_namespace init_user_ns;
15a793d79eSChristian Brauner 
16a793d79eSChristian Brauner /**
17a793d79eSChristian Brauner  * kuid_into_mnt - map a kuid down into a mnt_userns
18a793d79eSChristian Brauner  * @mnt_userns: user namespace of the relevant mount
19a793d79eSChristian Brauner  * @kuid: kuid to be mapped
20a793d79eSChristian Brauner  *
21a793d79eSChristian Brauner  * Return: @kuid mapped according to @mnt_userns.
22a793d79eSChristian Brauner  * If @kuid has no mapping INVALID_UID is returned.
23a793d79eSChristian Brauner  */
24a793d79eSChristian Brauner static inline kuid_t kuid_into_mnt(struct user_namespace *mnt_userns,
25a793d79eSChristian Brauner 				   kuid_t kuid)
26a793d79eSChristian Brauner {
27a793d79eSChristian Brauner 	return make_kuid(mnt_userns, __kuid_val(kuid));
28a793d79eSChristian Brauner }
29a793d79eSChristian Brauner 
30a793d79eSChristian Brauner /**
31a793d79eSChristian Brauner  * kgid_into_mnt - map a kgid down into a mnt_userns
32a793d79eSChristian Brauner  * @mnt_userns: user namespace of the relevant mount
33a793d79eSChristian Brauner  * @kgid: kgid to be mapped
34a793d79eSChristian Brauner  *
35a793d79eSChristian Brauner  * Return: @kgid mapped according to @mnt_userns.
36a793d79eSChristian Brauner  * If @kgid has no mapping INVALID_GID is returned.
37a793d79eSChristian Brauner  */
38a793d79eSChristian Brauner static inline kgid_t kgid_into_mnt(struct user_namespace *mnt_userns,
39a793d79eSChristian Brauner 				   kgid_t kgid)
40a793d79eSChristian Brauner {
41a793d79eSChristian Brauner 	return make_kgid(mnt_userns, __kgid_val(kgid));
42a793d79eSChristian Brauner }
43a793d79eSChristian Brauner 
44a793d79eSChristian Brauner /**
45a793d79eSChristian Brauner  * kuid_from_mnt - map a kuid up into a mnt_userns
46a793d79eSChristian Brauner  * @mnt_userns: user namespace of the relevant mount
47a793d79eSChristian Brauner  * @kuid: kuid to be mapped
48a793d79eSChristian Brauner  *
49a793d79eSChristian Brauner  * Return: @kuid mapped up according to @mnt_userns.
50a793d79eSChristian Brauner  * If @kuid has no mapping INVALID_UID is returned.
51a793d79eSChristian Brauner  */
52a793d79eSChristian Brauner static inline kuid_t kuid_from_mnt(struct user_namespace *mnt_userns,
53a793d79eSChristian Brauner 				   kuid_t kuid)
54a793d79eSChristian Brauner {
55a793d79eSChristian Brauner 	return KUIDT_INIT(from_kuid(mnt_userns, kuid));
56a793d79eSChristian Brauner }
57a793d79eSChristian Brauner 
58a793d79eSChristian Brauner /**
59a793d79eSChristian Brauner  * kgid_from_mnt - map a kgid up into a mnt_userns
60a793d79eSChristian Brauner  * @mnt_userns: user namespace of the relevant mount
61a793d79eSChristian Brauner  * @kgid: kgid to be mapped
62a793d79eSChristian Brauner  *
63a793d79eSChristian Brauner  * Return: @kgid mapped up according to @mnt_userns.
64a793d79eSChristian Brauner  * If @kgid has no mapping INVALID_GID is returned.
65a793d79eSChristian Brauner  */
66a793d79eSChristian Brauner static inline kgid_t kgid_from_mnt(struct user_namespace *mnt_userns,
67a793d79eSChristian Brauner 				   kgid_t kgid)
68a793d79eSChristian Brauner {
69a793d79eSChristian Brauner 	return KGIDT_INIT(from_kgid(mnt_userns, kgid));
70a793d79eSChristian Brauner }
71a793d79eSChristian Brauner 
72a793d79eSChristian Brauner /**
73*1ac2a410SChristian Brauner  * initial_idmapping - check whether this is the initial mapping
74*1ac2a410SChristian Brauner  * @ns: idmapping to check
75*1ac2a410SChristian Brauner  *
76*1ac2a410SChristian Brauner  * Check whether this is the initial mapping, mapping 0 to 0, 1 to 1,
77*1ac2a410SChristian Brauner  * [...], 1000 to 1000 [...].
78*1ac2a410SChristian Brauner  *
79*1ac2a410SChristian Brauner  * Return: true if this is the initial mapping, false if not.
80*1ac2a410SChristian Brauner  */
81*1ac2a410SChristian Brauner static inline bool initial_idmapping(const struct user_namespace *ns)
82*1ac2a410SChristian Brauner {
83*1ac2a410SChristian Brauner 	return ns == &init_user_ns;
84*1ac2a410SChristian Brauner }
85*1ac2a410SChristian Brauner 
86*1ac2a410SChristian Brauner /**
87*1ac2a410SChristian Brauner  * no_idmapping - check whether we can skip remapping a kuid/gid
88*1ac2a410SChristian Brauner  * @mnt_userns: the mount's idmapping
89*1ac2a410SChristian Brauner  * @fs_userns: the filesystem's idmapping
90*1ac2a410SChristian Brauner  *
91*1ac2a410SChristian Brauner  * This function can be used to check whether a remapping between two
92*1ac2a410SChristian Brauner  * idmappings is required.
93*1ac2a410SChristian Brauner  * An idmapped mount is a mount that has an idmapping attached to it that
94*1ac2a410SChristian Brauner  * is different from the filsystem's idmapping and the initial idmapping.
95*1ac2a410SChristian Brauner  * If the initial mapping is used or the idmapping of the mount and the
96*1ac2a410SChristian Brauner  * filesystem are identical no remapping is required.
97*1ac2a410SChristian Brauner  *
98*1ac2a410SChristian Brauner  * Return: true if remapping can be skipped, false if not.
99*1ac2a410SChristian Brauner  */
100*1ac2a410SChristian Brauner static inline bool no_idmapping(const struct user_namespace *mnt_userns,
101*1ac2a410SChristian Brauner 				const struct user_namespace *fs_userns)
102*1ac2a410SChristian Brauner {
103*1ac2a410SChristian Brauner 	return initial_idmapping(mnt_userns) || mnt_userns == fs_userns;
104*1ac2a410SChristian Brauner }
105*1ac2a410SChristian Brauner 
106*1ac2a410SChristian Brauner /**
107*1ac2a410SChristian Brauner  * mapped_kuid_fs - map a filesystem kuid into a mnt_userns
108*1ac2a410SChristian Brauner  * @mnt_userns: the mount's idmapping
109*1ac2a410SChristian Brauner  * @fs_userns: the filesystem's idmapping
110*1ac2a410SChristian Brauner  * @kuid : kuid to be mapped
111*1ac2a410SChristian Brauner  *
112*1ac2a410SChristian Brauner  * Take a @kuid and remap it from @fs_userns into @mnt_userns. Use this
113*1ac2a410SChristian Brauner  * function when preparing a @kuid to be reported to userspace.
114*1ac2a410SChristian Brauner  *
115*1ac2a410SChristian Brauner  * If no_idmapping() determines that this is not an idmapped mount we can
116*1ac2a410SChristian Brauner  * simply return @kuid unchanged.
117*1ac2a410SChristian Brauner  * If initial_idmapping() tells us that the filesystem is not mounted with an
118*1ac2a410SChristian Brauner  * idmapping we know the value of @kuid won't change when calling
119*1ac2a410SChristian Brauner  * from_kuid() so we can simply retrieve the value via __kuid_val()
120*1ac2a410SChristian Brauner  * directly.
121*1ac2a410SChristian Brauner  *
122*1ac2a410SChristian Brauner  * Return: @kuid mapped according to @mnt_userns.
123*1ac2a410SChristian Brauner  * If @kuid has no mapping in either @mnt_userns or @fs_userns INVALID_UID is
124*1ac2a410SChristian Brauner  * returned.
125*1ac2a410SChristian Brauner  */
126*1ac2a410SChristian Brauner static inline kuid_t mapped_kuid_fs(struct user_namespace *mnt_userns,
127*1ac2a410SChristian Brauner 				    struct user_namespace *fs_userns,
128*1ac2a410SChristian Brauner 				    kuid_t kuid)
129*1ac2a410SChristian Brauner {
130*1ac2a410SChristian Brauner 	uid_t uid;
131*1ac2a410SChristian Brauner 
132*1ac2a410SChristian Brauner 	if (no_idmapping(mnt_userns, fs_userns))
133*1ac2a410SChristian Brauner 		return kuid;
134*1ac2a410SChristian Brauner 	if (initial_idmapping(fs_userns))
135*1ac2a410SChristian Brauner 		uid = __kuid_val(kuid);
136*1ac2a410SChristian Brauner 	else
137*1ac2a410SChristian Brauner 		uid = from_kuid(fs_userns, kuid);
138*1ac2a410SChristian Brauner 	if (uid == (uid_t)-1)
139*1ac2a410SChristian Brauner 		return INVALID_UID;
140*1ac2a410SChristian Brauner 	return make_kuid(mnt_userns, uid);
141*1ac2a410SChristian Brauner }
142*1ac2a410SChristian Brauner 
143*1ac2a410SChristian Brauner /**
144*1ac2a410SChristian Brauner  * mapped_kgid_fs - map a filesystem kgid into a mnt_userns
145*1ac2a410SChristian Brauner  * @mnt_userns: the mount's idmapping
146*1ac2a410SChristian Brauner  * @fs_userns: the filesystem's idmapping
147*1ac2a410SChristian Brauner  * @kgid : kgid to be mapped
148*1ac2a410SChristian Brauner  *
149*1ac2a410SChristian Brauner  * Take a @kgid and remap it from @fs_userns into @mnt_userns. Use this
150*1ac2a410SChristian Brauner  * function when preparing a @kgid to be reported to userspace.
151*1ac2a410SChristian Brauner  *
152*1ac2a410SChristian Brauner  * If no_idmapping() determines that this is not an idmapped mount we can
153*1ac2a410SChristian Brauner  * simply return @kgid unchanged.
154*1ac2a410SChristian Brauner  * If initial_idmapping() tells us that the filesystem is not mounted with an
155*1ac2a410SChristian Brauner  * idmapping we know the value of @kgid won't change when calling
156*1ac2a410SChristian Brauner  * from_kgid() so we can simply retrieve the value via __kgid_val()
157*1ac2a410SChristian Brauner  * directly.
158*1ac2a410SChristian Brauner  *
159*1ac2a410SChristian Brauner  * Return: @kgid mapped according to @mnt_userns.
160*1ac2a410SChristian Brauner  * If @kgid has no mapping in either @mnt_userns or @fs_userns INVALID_GID is
161*1ac2a410SChristian Brauner  * returned.
162*1ac2a410SChristian Brauner  */
163*1ac2a410SChristian Brauner static inline kgid_t mapped_kgid_fs(struct user_namespace *mnt_userns,
164*1ac2a410SChristian Brauner 				    struct user_namespace *fs_userns,
165*1ac2a410SChristian Brauner 				    kgid_t kgid)
166*1ac2a410SChristian Brauner {
167*1ac2a410SChristian Brauner 	gid_t gid;
168*1ac2a410SChristian Brauner 
169*1ac2a410SChristian Brauner 	if (no_idmapping(mnt_userns, fs_userns))
170*1ac2a410SChristian Brauner 		return kgid;
171*1ac2a410SChristian Brauner 	if (initial_idmapping(fs_userns))
172*1ac2a410SChristian Brauner 		gid = __kgid_val(kgid);
173*1ac2a410SChristian Brauner 	else
174*1ac2a410SChristian Brauner 		gid = from_kgid(fs_userns, kgid);
175*1ac2a410SChristian Brauner 	if (gid == (gid_t)-1)
176*1ac2a410SChristian Brauner 		return INVALID_GID;
177*1ac2a410SChristian Brauner 	return make_kgid(mnt_userns, gid);
178*1ac2a410SChristian Brauner }
179*1ac2a410SChristian Brauner 
180*1ac2a410SChristian Brauner /**
181*1ac2a410SChristian Brauner  * mapped_kuid_user - map a user kuid into a mnt_userns
182*1ac2a410SChristian Brauner  * @mnt_userns: the mount's idmapping
183*1ac2a410SChristian Brauner  * @fs_userns: the filesystem's idmapping
184*1ac2a410SChristian Brauner  * @kuid : kuid to be mapped
185*1ac2a410SChristian Brauner  *
186*1ac2a410SChristian Brauner  * Use the idmapping of @mnt_userns to remap a @kuid into @fs_userns. Use this
187*1ac2a410SChristian Brauner  * function when preparing a @kuid to be written to disk or inode.
188*1ac2a410SChristian Brauner  *
189*1ac2a410SChristian Brauner  * If no_idmapping() determines that this is not an idmapped mount we can
190*1ac2a410SChristian Brauner  * simply return @kuid unchanged.
191*1ac2a410SChristian Brauner  * If initial_idmapping() tells us that the filesystem is not mounted with an
192*1ac2a410SChristian Brauner  * idmapping we know the value of @kuid won't change when calling
193*1ac2a410SChristian Brauner  * make_kuid() so we can simply retrieve the value via KUIDT_INIT()
194*1ac2a410SChristian Brauner  * directly.
195*1ac2a410SChristian Brauner  *
196*1ac2a410SChristian Brauner  * Return: @kuid mapped according to @mnt_userns.
197*1ac2a410SChristian Brauner  * If @kuid has no mapping in either @mnt_userns or @fs_userns INVALID_UID is
198*1ac2a410SChristian Brauner  * returned.
199*1ac2a410SChristian Brauner  */
200*1ac2a410SChristian Brauner static inline kuid_t mapped_kuid_user(struct user_namespace *mnt_userns,
201*1ac2a410SChristian Brauner 				      struct user_namespace *fs_userns,
202*1ac2a410SChristian Brauner 				      kuid_t kuid)
203*1ac2a410SChristian Brauner {
204*1ac2a410SChristian Brauner 	uid_t uid;
205*1ac2a410SChristian Brauner 
206*1ac2a410SChristian Brauner 	if (no_idmapping(mnt_userns, fs_userns))
207*1ac2a410SChristian Brauner 		return kuid;
208*1ac2a410SChristian Brauner 	uid = from_kuid(mnt_userns, kuid);
209*1ac2a410SChristian Brauner 	if (uid == (uid_t)-1)
210*1ac2a410SChristian Brauner 		return INVALID_UID;
211*1ac2a410SChristian Brauner 	if (initial_idmapping(fs_userns))
212*1ac2a410SChristian Brauner 		return KUIDT_INIT(uid);
213*1ac2a410SChristian Brauner 	return make_kuid(fs_userns, uid);
214*1ac2a410SChristian Brauner }
215*1ac2a410SChristian Brauner 
216*1ac2a410SChristian Brauner /**
217*1ac2a410SChristian Brauner  * mapped_kgid_user - map a user kgid into a mnt_userns
218*1ac2a410SChristian Brauner  * @mnt_userns: the mount's idmapping
219*1ac2a410SChristian Brauner  * @fs_userns: the filesystem's idmapping
220*1ac2a410SChristian Brauner  * @kgid : kgid to be mapped
221*1ac2a410SChristian Brauner  *
222*1ac2a410SChristian Brauner  * Use the idmapping of @mnt_userns to remap a @kgid into @fs_userns. Use this
223*1ac2a410SChristian Brauner  * function when preparing a @kgid to be written to disk or inode.
224*1ac2a410SChristian Brauner  *
225*1ac2a410SChristian Brauner  * If no_idmapping() determines that this is not an idmapped mount we can
226*1ac2a410SChristian Brauner  * simply return @kgid unchanged.
227*1ac2a410SChristian Brauner  * If initial_idmapping() tells us that the filesystem is not mounted with an
228*1ac2a410SChristian Brauner  * idmapping we know the value of @kgid won't change when calling
229*1ac2a410SChristian Brauner  * make_kgid() so we can simply retrieve the value via KGIDT_INIT()
230*1ac2a410SChristian Brauner  * directly.
231*1ac2a410SChristian Brauner  *
232*1ac2a410SChristian Brauner  * Return: @kgid mapped according to @mnt_userns.
233*1ac2a410SChristian Brauner  * If @kgid has no mapping in either @mnt_userns or @fs_userns INVALID_GID is
234*1ac2a410SChristian Brauner  * returned.
235*1ac2a410SChristian Brauner  */
236*1ac2a410SChristian Brauner static inline kgid_t mapped_kgid_user(struct user_namespace *mnt_userns,
237*1ac2a410SChristian Brauner 				      struct user_namespace *fs_userns,
238*1ac2a410SChristian Brauner 				      kgid_t kgid)
239*1ac2a410SChristian Brauner {
240*1ac2a410SChristian Brauner 	gid_t gid;
241*1ac2a410SChristian Brauner 
242*1ac2a410SChristian Brauner 	if (no_idmapping(mnt_userns, fs_userns))
243*1ac2a410SChristian Brauner 		return kgid;
244*1ac2a410SChristian Brauner 	gid = from_kgid(mnt_userns, kgid);
245*1ac2a410SChristian Brauner 	if (gid == (gid_t)-1)
246*1ac2a410SChristian Brauner 		return INVALID_GID;
247*1ac2a410SChristian Brauner 	if (initial_idmapping(fs_userns))
248*1ac2a410SChristian Brauner 		return KGIDT_INIT(gid);
249*1ac2a410SChristian Brauner 	return make_kgid(fs_userns, gid);
250*1ac2a410SChristian Brauner }
251*1ac2a410SChristian Brauner 
252*1ac2a410SChristian Brauner /**
253a793d79eSChristian Brauner  * mapped_fsuid - return caller's fsuid mapped up into a mnt_userns
254*1ac2a410SChristian Brauner  * @mnt_userns: the mount's idmapping
255a793d79eSChristian Brauner  *
256a793d79eSChristian Brauner  * Use this helper to initialize a new vfs or filesystem object based on
257a793d79eSChristian Brauner  * the caller's fsuid. A common example is initializing the i_uid field of
258a793d79eSChristian Brauner  * a newly allocated inode triggered by a creation event such as mkdir or
259a793d79eSChristian Brauner  * O_CREAT. Other examples include the allocation of quotas for a specific
260a793d79eSChristian Brauner  * user.
261a793d79eSChristian Brauner  *
262a793d79eSChristian Brauner  * Return: the caller's current fsuid mapped up according to @mnt_userns.
263a793d79eSChristian Brauner  */
264a793d79eSChristian Brauner static inline kuid_t mapped_fsuid(struct user_namespace *mnt_userns)
265a793d79eSChristian Brauner {
266*1ac2a410SChristian Brauner 	return mapped_kuid_user(mnt_userns, &init_user_ns, current_fsuid());
267a793d79eSChristian Brauner }
268a793d79eSChristian Brauner 
269a793d79eSChristian Brauner /**
270a793d79eSChristian Brauner  * mapped_fsgid - return caller's fsgid mapped up into a mnt_userns
271*1ac2a410SChristian Brauner  * @mnt_userns: the mount's idmapping
272a793d79eSChristian Brauner  *
273a793d79eSChristian Brauner  * Use this helper to initialize a new vfs or filesystem object based on
274a793d79eSChristian Brauner  * the caller's fsgid. A common example is initializing the i_gid field of
275a793d79eSChristian Brauner  * a newly allocated inode triggered by a creation event such as mkdir or
276a793d79eSChristian Brauner  * O_CREAT. Other examples include the allocation of quotas for a specific
277a793d79eSChristian Brauner  * user.
278a793d79eSChristian Brauner  *
279a793d79eSChristian Brauner  * Return: the caller's current fsgid mapped up according to @mnt_userns.
280a793d79eSChristian Brauner  */
281a793d79eSChristian Brauner static inline kgid_t mapped_fsgid(struct user_namespace *mnt_userns)
282a793d79eSChristian Brauner {
283*1ac2a410SChristian Brauner 	return mapped_kgid_user(mnt_userns, &init_user_ns, current_fsgid());
284a793d79eSChristian Brauner }
285a793d79eSChristian Brauner 
286a793d79eSChristian Brauner #endif /* _LINUX_MNT_IDMAPPING_H */
287