1
2
3
4
5
6
7
8
9
10
11
12
13
14
15#include <linux/kernel.h>
16#include <linux/slab.h>
17#include <linux/atomic.h>
18#include <linux/fs.h>
19#include <linux/sched.h>
20#include <linux/posix_acl.h>
21#include <linux/export.h>
22
23#include <linux/errno.h>
24
25EXPORT_SYMBOL(posix_acl_init);
26EXPORT_SYMBOL(posix_acl_alloc);
27EXPORT_SYMBOL(posix_acl_valid);
28EXPORT_SYMBOL(posix_acl_equiv_mode);
29EXPORT_SYMBOL(posix_acl_from_mode);
30
31struct posix_acl *get_acl(struct inode *inode, int type)
32{
33 struct posix_acl *acl;
34
35 acl = get_cached_acl(inode, type);
36 if (acl != ACL_NOT_CACHED)
37 return acl;
38
39 if (!IS_POSIXACL(inode))
40 return NULL;
41
42
43
44
45
46
47
48
49
50 if (!inode->i_op->get_acl) {
51 set_cached_acl(inode, type, NULL);
52 return NULL;
53 }
54 return inode->i_op->get_acl(inode, type);
55}
56EXPORT_SYMBOL(get_acl);
57
58
59
60
61void
62posix_acl_init(struct posix_acl *acl, int count)
63{
64 atomic_set(&acl->a_refcount, 1);
65 acl->a_count = count;
66}
67
68
69
70
71struct posix_acl *
72posix_acl_alloc(int count, gfp_t flags)
73{
74 const size_t size = sizeof(struct posix_acl) +
75 count * sizeof(struct posix_acl_entry);
76 struct posix_acl *acl = kmalloc(size, flags);
77 if (acl)
78 posix_acl_init(acl, count);
79 return acl;
80}
81
82
83
84
85static struct posix_acl *
86posix_acl_clone(const struct posix_acl *acl, gfp_t flags)
87{
88 struct posix_acl *clone = NULL;
89
90 if (acl) {
91 int size = sizeof(struct posix_acl) + acl->a_count *
92 sizeof(struct posix_acl_entry);
93 clone = kmemdup(acl, size, flags);
94 if (clone)
95 atomic_set(&clone->a_refcount, 1);
96 }
97 return clone;
98}
99
100
101
102
103int
104posix_acl_valid(const struct posix_acl *acl)
105{
106 const struct posix_acl_entry *pa, *pe;
107 int state = ACL_USER_OBJ;
108 kuid_t prev_uid = INVALID_UID;
109 kgid_t prev_gid = INVALID_GID;
110 int needs_mask = 0;
111
112 FOREACH_ACL_ENTRY(pa, acl, pe) {
113 if (pa->e_perm & ~(ACL_READ|ACL_WRITE|ACL_EXECUTE))
114 return -EINVAL;
115 switch (pa->e_tag) {
116 case ACL_USER_OBJ:
117 if (state == ACL_USER_OBJ) {
118 state = ACL_USER;
119 break;
120 }
121 return -EINVAL;
122
123 case ACL_USER:
124 if (state != ACL_USER)
125 return -EINVAL;
126 if (!uid_valid(pa->e_uid))
127 return -EINVAL;
128 if (uid_valid(prev_uid) &&
129 uid_lte(pa->e_uid, prev_uid))
130 return -EINVAL;
131 prev_uid = pa->e_uid;
132 needs_mask = 1;
133 break;
134
135 case ACL_GROUP_OBJ:
136 if (state == ACL_USER) {
137 state = ACL_GROUP;
138 break;
139 }
140 return -EINVAL;
141
142 case ACL_GROUP:
143 if (state != ACL_GROUP)
144 return -EINVAL;
145 if (!gid_valid(pa->e_gid))
146 return -EINVAL;
147 if (gid_valid(prev_gid) &&
148 gid_lte(pa->e_gid, prev_gid))
149 return -EINVAL;
150 prev_gid = pa->e_gid;
151 needs_mask = 1;
152 break;
153
154 case ACL_MASK:
155 if (state != ACL_GROUP)
156 return -EINVAL;
157 state = ACL_OTHER;
158 break;
159
160 case ACL_OTHER:
161 if (state == ACL_OTHER ||
162 (state == ACL_GROUP && !needs_mask)) {
163 state = 0;
164 break;
165 }
166 return -EINVAL;
167
168 default:
169 return -EINVAL;
170 }
171 }
172 if (state == 0)
173 return 0;
174 return -EINVAL;
175}
176
177
178
179
180
181int
182posix_acl_equiv_mode(const struct posix_acl *acl, umode_t *mode_p)
183{
184 const struct posix_acl_entry *pa, *pe;
185 umode_t mode = 0;
186 int not_equiv = 0;
187
188 FOREACH_ACL_ENTRY(pa, acl, pe) {
189 switch (pa->e_tag) {
190 case ACL_USER_OBJ:
191 mode |= (pa->e_perm & S_IRWXO) << 6;
192 break;
193 case ACL_GROUP_OBJ:
194 mode |= (pa->e_perm & S_IRWXO) << 3;
195 break;
196 case ACL_OTHER:
197 mode |= pa->e_perm & S_IRWXO;
198 break;
199 case ACL_MASK:
200 mode = (mode & ~S_IRWXG) |
201 ((pa->e_perm & S_IRWXO) << 3);
202 not_equiv = 1;
203 break;
204 case ACL_USER:
205 case ACL_GROUP:
206 not_equiv = 1;
207 break;
208 default:
209 return -EINVAL;
210 }
211 }
212 if (mode_p)
213 *mode_p = (*mode_p & ~S_IRWXUGO) | mode;
214 return not_equiv;
215}
216
217
218
219
220struct posix_acl *
221posix_acl_from_mode(umode_t mode, gfp_t flags)
222{
223 struct posix_acl *acl = posix_acl_alloc(3, flags);
224 if (!acl)
225 return ERR_PTR(-ENOMEM);
226
227 acl->a_entries[0].e_tag = ACL_USER_OBJ;
228 acl->a_entries[0].e_perm = (mode & S_IRWXU) >> 6;
229
230 acl->a_entries[1].e_tag = ACL_GROUP_OBJ;
231 acl->a_entries[1].e_perm = (mode & S_IRWXG) >> 3;
232
233 acl->a_entries[2].e_tag = ACL_OTHER;
234 acl->a_entries[2].e_perm = (mode & S_IRWXO);
235 return acl;
236}
237
238
239
240
241
242int
243posix_acl_permission(struct inode *inode, const struct posix_acl *acl, int want)
244{
245 const struct posix_acl_entry *pa, *pe, *mask_obj;
246 int found = 0;
247
248 want &= MAY_READ | MAY_WRITE | MAY_EXEC | MAY_NOT_BLOCK;
249
250 FOREACH_ACL_ENTRY(pa, acl, pe) {
251 switch(pa->e_tag) {
252 case ACL_USER_OBJ:
253
254 if (uid_eq(inode->i_uid, current_fsuid()))
255 goto check_perm;
256 break;
257 case ACL_USER:
258 if (uid_eq(pa->e_uid, current_fsuid()))
259 goto mask;
260 break;
261 case ACL_GROUP_OBJ:
262 if (in_group_p(inode->i_gid)) {
263 found = 1;
264 if ((pa->e_perm & want) == want)
265 goto mask;
266 }
267 break;
268 case ACL_GROUP:
269 if (in_group_p(pa->e_gid)) {
270 found = 1;
271 if ((pa->e_perm & want) == want)
272 goto mask;
273 }
274 break;
275 case ACL_MASK:
276 break;
277 case ACL_OTHER:
278 if (found)
279 return -EACCES;
280 else
281 goto check_perm;
282 default:
283 return -EIO;
284 }
285 }
286 return -EIO;
287
288mask:
289 for (mask_obj = pa+1; mask_obj != pe; mask_obj++) {
290 if (mask_obj->e_tag == ACL_MASK) {
291 if ((pa->e_perm & mask_obj->e_perm & want) == want)
292 return 0;
293 return -EACCES;
294 }
295 }
296
297check_perm:
298 if ((pa->e_perm & want) == want)
299 return 0;
300 return -EACCES;
301}
302
303
304
305
306
307
308
309
310
311static int posix_acl_create_masq(struct posix_acl *acl, umode_t *mode_p)
312{
313 struct posix_acl_entry *pa, *pe;
314 struct posix_acl_entry *group_obj = NULL, *mask_obj = NULL;
315 umode_t mode = *mode_p;
316 int not_equiv = 0;
317
318
319
320 FOREACH_ACL_ENTRY(pa, acl, pe) {
321 switch(pa->e_tag) {
322 case ACL_USER_OBJ:
323 pa->e_perm &= (mode >> 6) | ~S_IRWXO;
324 mode &= (pa->e_perm << 6) | ~S_IRWXU;
325 break;
326
327 case ACL_USER:
328 case ACL_GROUP:
329 not_equiv = 1;
330 break;
331
332 case ACL_GROUP_OBJ:
333 group_obj = pa;
334 break;
335
336 case ACL_OTHER:
337 pa->e_perm &= mode | ~S_IRWXO;
338 mode &= pa->e_perm | ~S_IRWXO;
339 break;
340
341 case ACL_MASK:
342 mask_obj = pa;
343 not_equiv = 1;
344 break;
345
346 default:
347 return -EIO;
348 }
349 }
350
351 if (mask_obj) {
352 mask_obj->e_perm &= (mode >> 3) | ~S_IRWXO;
353 mode &= (mask_obj->e_perm << 3) | ~S_IRWXG;
354 } else {
355 if (!group_obj)
356 return -EIO;
357 group_obj->e_perm &= (mode >> 3) | ~S_IRWXO;
358 mode &= (group_obj->e_perm << 3) | ~S_IRWXG;
359 }
360
361 *mode_p = (*mode_p & ~S_IRWXUGO) | mode;
362 return not_equiv;
363}
364
365
366
367
368static int posix_acl_chmod_masq(struct posix_acl *acl, umode_t mode)
369{
370 struct posix_acl_entry *group_obj = NULL, *mask_obj = NULL;
371 struct posix_acl_entry *pa, *pe;
372
373
374
375 FOREACH_ACL_ENTRY(pa, acl, pe) {
376 switch(pa->e_tag) {
377 case ACL_USER_OBJ:
378 pa->e_perm = (mode & S_IRWXU) >> 6;
379 break;
380
381 case ACL_USER:
382 case ACL_GROUP:
383 break;
384
385 case ACL_GROUP_OBJ:
386 group_obj = pa;
387 break;
388
389 case ACL_MASK:
390 mask_obj = pa;
391 break;
392
393 case ACL_OTHER:
394 pa->e_perm = (mode & S_IRWXO);
395 break;
396
397 default:
398 return -EIO;
399 }
400 }
401
402 if (mask_obj) {
403 mask_obj->e_perm = (mode & S_IRWXG) >> 3;
404 } else {
405 if (!group_obj)
406 return -EIO;
407 group_obj->e_perm = (mode & S_IRWXG) >> 3;
408 }
409
410 return 0;
411}
412
413int
414posix_acl_create(struct posix_acl **acl, gfp_t gfp, umode_t *mode_p)
415{
416 struct posix_acl *clone = posix_acl_clone(*acl, gfp);
417 int err = -ENOMEM;
418 if (clone) {
419 err = posix_acl_create_masq(clone, mode_p);
420 if (err < 0) {
421 posix_acl_release(clone);
422 clone = NULL;
423 }
424 }
425 posix_acl_release(*acl);
426 *acl = clone;
427 return err;
428}
429EXPORT_SYMBOL(posix_acl_create);
430
431
432
433
434
435
436
437
438
439
440
441
442
443int posix_acl_update_mode(struct inode *inode, umode_t *mode_p,
444 struct posix_acl **acl)
445{
446 umode_t mode = inode->i_mode;
447 int error;
448
449 error = posix_acl_equiv_mode(*acl, &mode);
450 if (error < 0)
451 return error;
452 if (error == 0)
453 *acl = NULL;
454 if (!in_group_p(inode->i_gid) &&
455 !capable_wrt_inode_uidgid(inode, CAP_FSETID))
456 mode &= ~S_ISGID;
457 *mode_p = mode;
458 return 0;
459}
460EXPORT_SYMBOL(posix_acl_update_mode);
461
462int
463posix_acl_chmod(struct posix_acl **acl, gfp_t gfp, umode_t mode)
464{
465 struct posix_acl *clone = posix_acl_clone(*acl, gfp);
466 int err = -ENOMEM;
467 if (clone) {
468 err = posix_acl_chmod_masq(clone, mode);
469 if (err) {
470 posix_acl_release(clone);
471 clone = NULL;
472 }
473 }
474 posix_acl_release(*acl);
475 *acl = clone;
476 return err;
477}
478EXPORT_SYMBOL(posix_acl_chmod);
479