summaryrefslogtreecommitdiff
path: root/include/linux/mnt_idmapping.h
blob: cd4d5c8781f54e0531bf713fd2d2957c97e41f63 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _LINUX_MNT_IDMAPPING_H
#define _LINUX_MNT_IDMAPPING_H

#include <linux/types.h>
#include <linux/uidgid.h>

struct mnt_idmap;
struct user_namespace;

extern struct mnt_idmap nop_mnt_idmap;
extern struct user_namespace init_user_ns;

typedef struct {
	uid_t val;
} vfsuid_t;

typedef struct {
	gid_t val;
} vfsgid_t;

static_assert(sizeof(vfsuid_t) == sizeof(kuid_t));
static_assert(sizeof(vfsgid_t) == sizeof(kgid_t));
static_assert(offsetof(vfsuid_t, val) == offsetof(kuid_t, val));
static_assert(offsetof(vfsgid_t, val) == offsetof(kgid_t, val));

#ifdef CONFIG_MULTIUSER
static inline uid_t __vfsuid_val(vfsuid_t uid)
{
	return uid.val;
}

static inline gid_t __vfsgid_val(vfsgid_t gid)
{
	return gid.val;
}
#else
static inline uid_t __vfsuid_val(vfsuid_t uid)
{
	return 0;
}

static inline gid_t __vfsgid_val(vfsgid_t gid)
{
	return 0;
}
#endif

static inline bool vfsuid_valid(vfsuid_t uid)
{
	return __vfsuid_val(uid) != (uid_t)-1;
}

static inline bool vfsgid_valid(vfsgid_t gid)
{
	return __vfsgid_val(gid) != (gid_t)-1;
}

static inline bool vfsuid_eq(vfsuid_t left, vfsuid_t right)
{
	return vfsuid_valid(left) && __vfsuid_val(left) == __vfsuid_val(right);
}

static inline bool vfsgid_eq(vfsgid_t left, vfsgid_t right)
{
	return vfsgid_valid(left) && __vfsgid_val(left) == __vfsgid_val(right);
}

/**
 * vfsuid_eq_kuid - check whether kuid and vfsuid have the same value
 * @vfsuid: the vfsuid to compare
 * @kuid: the kuid to compare
 *
 * Check whether @vfsuid and @kuid have the same values.
 *
 * Return: true if @vfsuid and @kuid have the same value, false if not.
 * Comparison between two invalid uids returns false.
 */
static inline bool vfsuid_eq_kuid(vfsuid_t vfsuid, kuid_t kuid)
{
	return vfsuid_valid(vfsuid) && __vfsuid_val(vfsuid) == __kuid_val(kuid);
}

/**
 * vfsgid_eq_kgid - check whether kgid and vfsgid have the same value
 * @vfsgid: the vfsgid to compare
 * @kgid: the kgid to compare
 *
 * Check whether @vfsgid and @kgid have the same values.
 *
 * Return: true if @vfsgid and @kgid have the same value, false if not.
 * Comparison between two invalid gids returns false.
 */
static inline bool vfsgid_eq_kgid(vfsgid_t vfsgid, kgid_t kgid)
{
	return vfsgid_valid(vfsgid) && __vfsgid_val(vfsgid) == __kgid_val(kgid);
}

/*
 * vfs{g,u}ids are created from k{g,u}ids.
 * We don't allow them to be created from regular {u,g}id.
 */
#define VFSUIDT_INIT(val) (vfsuid_t){ __kuid_val(val) }
#define VFSGIDT_INIT(val) (vfsgid_t){ __kgid_val(val) }

#define INVALID_VFSUID VFSUIDT_INIT(INVALID_UID)
#define INVALID_VFSGID VFSGIDT_INIT(INVALID_GID)

/*
 * Allow a vfs{g,u}id to be used as a k{g,u}id where we want to compare
 * whether the mapped value is identical to value of a k{g,u}id.
 */
#define AS_KUIDT(val) (kuid_t){ __vfsuid_val(val) }
#define AS_KGIDT(val) (kgid_t){ __vfsgid_val(val) }

int vfsgid_in_group_p(vfsgid_t vfsgid);

struct mnt_idmap *mnt_idmap_get(struct mnt_idmap *idmap);
void mnt_idmap_put(struct mnt_idmap *idmap);

vfsuid_t make_vfsuid(struct mnt_idmap *idmap,
		     struct user_namespace *fs_userns, kuid_t kuid);

vfsgid_t make_vfsgid(struct mnt_idmap *idmap,
		     struct user_namespace *fs_userns, kgid_t kgid);

kuid_t from_vfsuid(struct mnt_idmap *idmap,
		   struct user_namespace *fs_userns, vfsuid_t vfsuid);

kgid_t from_vfsgid(struct mnt_idmap *idmap,
		   struct user_namespace *fs_userns, vfsgid_t vfsgid);

/**
 * vfsuid_has_fsmapping - check whether a vfsuid maps into the filesystem
 * @idmap: the mount's idmapping
 * @fs_userns: the filesystem's idmapping
 * @vfsuid: vfsuid to be mapped
 *
 * Check whether @vfsuid has a mapping in the filesystem idmapping. Use this
 * function to check whether the filesystem idmapping has a mapping for
 * @vfsuid.
 *
 * Return: true if @vfsuid has a mapping in the filesystem, false if not.
 */
static inline bool vfsuid_has_fsmapping(struct mnt_idmap *idmap,
					struct user_namespace *fs_userns,
					vfsuid_t vfsuid)
{
	return uid_valid(from_vfsuid(idmap, fs_userns, vfsuid));
}

static inline bool vfsuid_has_mapping(struct user_namespace *userns,
				      vfsuid_t vfsuid)
{
	return from_kuid(userns, AS_KUIDT(vfsuid)) != (uid_t)-1;
}

/**
 * vfsuid_into_kuid - convert vfsuid into kuid
 * @vfsuid: the vfsuid to convert
 *
 * This can be used when a vfsuid is committed as a kuid.
 *
 * Return: a kuid with the value of @vfsuid
 */
static inline kuid_t vfsuid_into_kuid(vfsuid_t vfsuid)
{
	return AS_KUIDT(vfsuid);
}

/**
 * vfsgid_has_fsmapping - check whether a vfsgid maps into the filesystem
 * @idmap: the mount's idmapping
 * @fs_userns: the filesystem's idmapping
 * @vfsgid: vfsgid to be mapped
 *
 * Check whether @vfsgid has a mapping in the filesystem idmapping. Use this
 * function to check whether the filesystem idmapping has a mapping for
 * @vfsgid.
 *
 * Return: true if @vfsgid has a mapping in the filesystem, false if not.
 */
static inline bool vfsgid_has_fsmapping(struct mnt_idmap *idmap,
					struct user_namespace *fs_userns,
					vfsgid_t vfsgid)
{
	return gid_valid(from_vfsgid(idmap, fs_userns, vfsgid));
}

static inline bool vfsgid_has_mapping(struct user_namespace *userns,
				      vfsgid_t vfsgid)
{
	return from_kgid(userns, AS_KGIDT(vfsgid)) != (gid_t)-1;
}

/**
 * vfsgid_into_kgid - convert vfsgid into kgid
 * @vfsgid: the vfsgid to convert
 *
 * This can be used when a vfsgid is committed as a kgid.
 *
 * Return: a kgid with the value of @vfsgid
 */
static inline kgid_t vfsgid_into_kgid(vfsgid_t vfsgid)
{
	return AS_KGIDT(vfsgid);
}

/**
 * mapped_fsuid - return caller's fsuid mapped according to an idmapping
 * @idmap: the mount's idmapping
 * @fs_userns: the filesystem's idmapping
 *
 * Use this helper to initialize a new vfs or filesystem object based on
 * the caller's fsuid. A common example is initializing the i_uid field of
 * a newly allocated inode triggered by a creation event such as mkdir or
 * O_CREAT. Other examples include the allocation of quotas for a specific
 * user.
 *
 * Return: the caller's current fsuid mapped up according to @idmap.
 */
static inline kuid_t mapped_fsuid(struct mnt_idmap *idmap,
				  struct user_namespace *fs_userns)
{
	return from_vfsuid(idmap, fs_userns, VFSUIDT_INIT(current_fsuid()));
}

/**
 * mapped_fsgid - return caller's fsgid mapped according to an idmapping
 * @idmap: the mount's idmapping
 * @fs_userns: the filesystem's idmapping
 *
 * Use this helper to initialize a new vfs or filesystem object based on
 * the caller's fsgid. A common example is initializing the i_gid field of
 * a newly allocated inode triggered by a creation event such as mkdir or
 * O_CREAT. Other examples include the allocation of quotas for a specific
 * user.
 *
 * Return: the caller's current fsgid mapped up according to @idmap.
 */
static inline kgid_t mapped_fsgid(struct mnt_idmap *idmap,
				  struct user_namespace *fs_userns)
{
	return from_vfsgid(idmap, fs_userns, VFSGIDT_INIT(current_fsgid()));
}

#endif /* _LINUX_MNT_IDMAPPING_H */