]>
git.ipfire.org Git - thirdparty/linux.git/blob - fs/mnt_idmapping.c
1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright (c) 2022 Christian Brauner <brauner@kernel.org> */
4 #include <linux/cred.h>
6 #include <linux/mnt_idmapping.h>
7 #include <linux/slab.h>
8 #include <linux/user_namespace.h>
13 struct user_namespace
*owner
;
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, [...].
22 struct mnt_idmap nop_mnt_idmap
= {
23 .owner
= &init_user_ns
,
24 .count
= REFCOUNT_INIT(1),
26 EXPORT_SYMBOL_GPL(nop_mnt_idmap
);
29 * check_fsmapping - check whether an mount idmapping is allowed
30 * @idmap: idmap of the relevent mount
31 * @sb: super block of the filesystem
33 * Return: true if @idmap is allowed, false if not.
35 bool check_fsmapping(const struct mnt_idmap
*idmap
,
36 const struct super_block
*sb
)
38 return idmap
->owner
!= sb
->s_user_ns
;
42 * initial_idmapping - check whether this is the initial mapping
43 * @ns: idmapping to check
45 * Check whether this is the initial mapping, mapping 0 to 0, 1 to 1,
46 * [...], 1000 to 1000 [...].
48 * Return: true if this is the initial mapping, false if not.
50 static inline bool initial_idmapping(const struct user_namespace
*ns
)
52 return ns
== &init_user_ns
;
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
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.
67 * Return: true if remapping can be skipped, false if not.
69 static inline bool no_idmapping(const struct user_namespace
*mnt_userns
,
70 const struct user_namespace
*fs_userns
)
72 return initial_idmapping(mnt_userns
) || mnt_userns
== fs_userns
;
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
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.
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()
91 * Return: @kuid mapped according to @idmap.
92 * If @kuid has no mapping in either @idmap or @fs_userns INVALID_UID is
96 vfsuid_t
make_vfsuid(struct mnt_idmap
*idmap
,
97 struct user_namespace
*fs_userns
,
101 struct user_namespace
*mnt_userns
= idmap
->owner
;
103 if (no_idmapping(mnt_userns
, fs_userns
))
104 return VFSUIDT_INIT(kuid
);
105 if (initial_idmapping(fs_userns
))
106 uid
= __kuid_val(kuid
);
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
));
113 EXPORT_SYMBOL_GPL(make_vfsuid
);
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
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.
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()
131 * Return: @kgid mapped according to @idmap.
132 * If @kgid has no mapping in either @idmap or @fs_userns INVALID_GID is
135 vfsgid_t
make_vfsgid(struct mnt_idmap
*idmap
,
136 struct user_namespace
*fs_userns
, kgid_t kgid
)
139 struct user_namespace
*mnt_userns
= idmap
->owner
;
141 if (no_idmapping(mnt_userns
, fs_userns
))
142 return VFSGIDT_INIT(kgid
);
143 if (initial_idmapping(fs_userns
))
144 gid
= __kgid_val(kgid
);
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
));
151 EXPORT_SYMBOL_GPL(make_vfsgid
);
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
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.
162 * Return: @vfsuid mapped into the filesystem idmapping
164 kuid_t
from_vfsuid(struct mnt_idmap
*idmap
,
165 struct user_namespace
*fs_userns
, vfsuid_t vfsuid
)
168 struct user_namespace
*mnt_userns
= idmap
->owner
;
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)
175 if (initial_idmapping(fs_userns
))
176 return KUIDT_INIT(uid
);
177 return make_kuid(fs_userns
, uid
);
179 EXPORT_SYMBOL_GPL(from_vfsuid
);
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
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.
190 * Return: @vfsgid mapped into the filesystem idmapping
192 kgid_t
from_vfsgid(struct mnt_idmap
*idmap
,
193 struct user_namespace
*fs_userns
, vfsgid_t vfsgid
)
196 struct user_namespace
*mnt_userns
= idmap
->owner
;
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)
203 if (initial_idmapping(fs_userns
))
204 return KGIDT_INIT(gid
);
205 return make_kgid(fs_userns
, gid
);
207 EXPORT_SYMBOL_GPL(from_vfsgid
);
209 #ifdef CONFIG_MULTIUSER
211 * vfsgid_in_group_p() - check whether a vfsuid matches the caller's groups
212 * @vfsgid: the mnt gid to match
214 * This function can be used to determine whether @vfsuid matches any of the
217 * Return: 1 if vfsuid matches caller's groups, 0 if not.
219 int vfsgid_in_group_p(vfsgid_t vfsgid
)
221 return in_group_p(AS_KGIDT(vfsgid
));
224 int vfsgid_in_group_p(vfsgid_t vfsgid
)
229 EXPORT_SYMBOL_GPL(vfsgid_in_group_p
);
231 struct mnt_idmap
*alloc_mnt_idmap(struct user_namespace
*mnt_userns
)
233 struct mnt_idmap
*idmap
;
235 idmap
= kzalloc(sizeof(struct mnt_idmap
), GFP_KERNEL_ACCOUNT
);
237 return ERR_PTR(-ENOMEM
);
239 idmap
->owner
= get_user_ns(mnt_userns
);
240 refcount_set(&idmap
->count
, 1);
245 * mnt_idmap_get - get a reference to an idmapping
246 * @idmap: the idmap to bump the reference on
248 * If @idmap is not the @nop_mnt_idmap bump the reference count.
250 * Return: @idmap with reference count bumped if @not_mnt_idmap isn't passed.
252 struct mnt_idmap
*mnt_idmap_get(struct mnt_idmap
*idmap
)
254 if (idmap
!= &nop_mnt_idmap
)
255 refcount_inc(&idmap
->count
);
259 EXPORT_SYMBOL_GPL(mnt_idmap_get
);
262 * mnt_idmap_put - put a reference to an idmapping
263 * @idmap: the idmap to put the reference on
265 * If this is a non-initial idmapping, put the reference count when a mount is
266 * released and free it if we're the last user.
268 void mnt_idmap_put(struct mnt_idmap
*idmap
)
270 if (idmap
!= &nop_mnt_idmap
&& refcount_dec_and_test(&idmap
->count
)) {
271 put_user_ns(idmap
->owner
);
275 EXPORT_SYMBOL_GPL(mnt_idmap_put
);