~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/fs/posix_acl.c

Version: ~ [ linux-5.7 ] ~ [ linux-5.6.15 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.43 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.125 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.182 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.225 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.225 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.19.8 ] ~ [ linux-3.18.140 ] ~ [ linux-3.17.8 ] ~ [ linux-3.16.84 ] ~ [ linux-3.15.10 ] ~ [ linux-3.14.79 ] ~ [ linux-3.13.11 ] ~ [ linux-3.12.74 ] ~ [ linux-3.11.10 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /*
  2  * Copyright (C) 2002,2003 by Andreas Gruenbacher <a.gruenbacher@computer.org>
  3  *
  4  * Fixes from William Schumacher incorporated on 15 March 2001.
  5  *    (Reported by Charles Bertsch, <CBertsch@microtest.com>).
  6  */
  7 
  8 /*
  9  *  This file contains generic functions for manipulating
 10  *  POSIX 1003.1e draft standard 17 ACLs.
 11  */
 12 
 13 #include <linux/kernel.h>
 14 #include <linux/slab.h>
 15 #include <linux/atomic.h>
 16 #include <linux/fs.h>
 17 #include <linux/sched.h>
 18 #include <linux/cred.h>
 19 #include <linux/posix_acl.h>
 20 #include <linux/posix_acl_xattr.h>
 21 #include <linux/xattr.h>
 22 #include <linux/export.h>
 23 #include <linux/user_namespace.h>
 24 
 25 static struct posix_acl **acl_by_type(struct inode *inode, int type)
 26 {
 27         switch (type) {
 28         case ACL_TYPE_ACCESS:
 29                 return &inode->i_acl;
 30         case ACL_TYPE_DEFAULT:
 31                 return &inode->i_default_acl;
 32         default:
 33                 BUG();
 34         }
 35 }
 36 
 37 struct posix_acl *get_cached_acl(struct inode *inode, int type)
 38 {
 39         struct posix_acl **p = acl_by_type(inode, type);
 40         struct posix_acl *acl;
 41 
 42         for (;;) {
 43                 rcu_read_lock();
 44                 acl = rcu_dereference(*p);
 45                 if (!acl || is_uncached_acl(acl) ||
 46                     refcount_inc_not_zero(&acl->a_refcount))
 47                         break;
 48                 rcu_read_unlock();
 49                 cpu_relax();
 50         }
 51         rcu_read_unlock();
 52         return acl;
 53 }
 54 EXPORT_SYMBOL(get_cached_acl);
 55 
 56 struct posix_acl *get_cached_acl_rcu(struct inode *inode, int type)
 57 {
 58         return rcu_dereference(*acl_by_type(inode, type));
 59 }
 60 EXPORT_SYMBOL(get_cached_acl_rcu);
 61 
 62 void set_cached_acl(struct inode *inode, int type, struct posix_acl *acl)
 63 {
 64         struct posix_acl **p = acl_by_type(inode, type);
 65         struct posix_acl *old;
 66 
 67         old = xchg(p, posix_acl_dup(acl));
 68         if (!is_uncached_acl(old))
 69                 posix_acl_release(old);
 70 }
 71 EXPORT_SYMBOL(set_cached_acl);
 72 
 73 static void __forget_cached_acl(struct posix_acl **p)
 74 {
 75         struct posix_acl *old;
 76 
 77         old = xchg(p, ACL_NOT_CACHED);
 78         if (!is_uncached_acl(old))
 79                 posix_acl_release(old);
 80 }
 81 
 82 void forget_cached_acl(struct inode *inode, int type)
 83 {
 84         __forget_cached_acl(acl_by_type(inode, type));
 85 }
 86 EXPORT_SYMBOL(forget_cached_acl);
 87 
 88 void forget_all_cached_acls(struct inode *inode)
 89 {
 90         __forget_cached_acl(&inode->i_acl);
 91         __forget_cached_acl(&inode->i_default_acl);
 92 }
 93 EXPORT_SYMBOL(forget_all_cached_acls);
 94 
 95 struct posix_acl *get_acl(struct inode *inode, int type)
 96 {
 97         void *sentinel;
 98         struct posix_acl **p;
 99         struct posix_acl *acl;
100 
101         /*
102          * The sentinel is used to detect when another operation like
103          * set_cached_acl() or forget_cached_acl() races with get_acl().
104          * It is guaranteed that is_uncached_acl(sentinel) is true.
105          */
106 
107         acl = get_cached_acl(inode, type);
108         if (!is_uncached_acl(acl))
109                 return acl;
110 
111         if (!IS_POSIXACL(inode))
112                 return NULL;
113 
114         sentinel = uncached_acl_sentinel(current);
115         p = acl_by_type(inode, type);
116 
117         /*
118          * If the ACL isn't being read yet, set our sentinel.  Otherwise, the
119          * current value of the ACL will not be ACL_NOT_CACHED and so our own
120          * sentinel will not be set; another task will update the cache.  We
121          * could wait for that other task to complete its job, but it's easier
122          * to just call ->get_acl to fetch the ACL ourself.  (This is going to
123          * be an unlikely race.)
124          */
125         if (cmpxchg(p, ACL_NOT_CACHED, sentinel) != ACL_NOT_CACHED)
126                 /* fall through */ ;
127 
128         /*
129          * Normally, the ACL returned by ->get_acl will be cached.
130          * A filesystem can prevent that by calling
131          * forget_cached_acl(inode, type) in ->get_acl.
132          *
133          * If the filesystem doesn't have a get_acl() function at all, we'll
134          * just create the negative cache entry.
135          */
136         if (!inode->i_op->get_acl) {
137                 set_cached_acl(inode, type, NULL);
138                 return NULL;
139         }
140         acl = inode->i_op->get_acl(inode, type);
141 
142         if (IS_ERR(acl)) {
143                 /*
144                  * Remove our sentinel so that we don't block future attempts
145                  * to cache the ACL.
146                  */
147                 cmpxchg(p, sentinel, ACL_NOT_CACHED);
148                 return acl;
149         }
150 
151         /*
152          * Cache the result, but only if our sentinel is still in place.
153          */
154         posix_acl_dup(acl);
155         if (unlikely(cmpxchg(p, sentinel, acl) != sentinel))
156                 posix_acl_release(acl);
157         return acl;
158 }
159 EXPORT_SYMBOL(get_acl);
160 
161 /*
162  * Init a fresh posix_acl
163  */
164 void
165 posix_acl_init(struct posix_acl *acl, int count)
166 {
167         refcount_set(&acl->a_refcount, 1);
168         acl->a_count = count;
169 }
170 EXPORT_SYMBOL(posix_acl_init);
171 
172 /*
173  * Allocate a new ACL with the specified number of entries.
174  */
175 struct posix_acl *
176 posix_acl_alloc(int count, gfp_t flags)
177 {
178         const size_t size = sizeof(struct posix_acl) +
179                             count * sizeof(struct posix_acl_entry);
180         struct posix_acl *acl = kmalloc(size, flags);
181         if (acl)
182                 posix_acl_init(acl, count);
183         return acl;
184 }
185 EXPORT_SYMBOL(posix_acl_alloc);
186 
187 /*
188  * Clone an ACL.
189  */
190 static struct posix_acl *
191 posix_acl_clone(const struct posix_acl *acl, gfp_t flags)
192 {
193         struct posix_acl *clone = NULL;
194 
195         if (acl) {
196                 int size = sizeof(struct posix_acl) + acl->a_count *
197                            sizeof(struct posix_acl_entry);
198                 clone = kmemdup(acl, size, flags);
199                 if (clone)
200                         refcount_set(&clone->a_refcount, 1);
201         }
202         return clone;
203 }
204 
205 /*
206  * Check if an acl is valid. Returns 0 if it is, or -E... otherwise.
207  */
208 int
209 posix_acl_valid(struct user_namespace *user_ns, const struct posix_acl *acl)
210 {
211         const struct posix_acl_entry *pa, *pe;
212         int state = ACL_USER_OBJ;
213         int needs_mask = 0;
214 
215         FOREACH_ACL_ENTRY(pa, acl, pe) {
216                 if (pa->e_perm & ~(ACL_READ|ACL_WRITE|ACL_EXECUTE))
217                         return -EINVAL;
218                 switch (pa->e_tag) {
219                         case ACL_USER_OBJ:
220                                 if (state == ACL_USER_OBJ) {
221                                         state = ACL_USER;
222                                         break;
223                                 }
224                                 return -EINVAL;
225 
226                         case ACL_USER:
227                                 if (state != ACL_USER)
228                                         return -EINVAL;
229                                 if (!kuid_has_mapping(user_ns, pa->e_uid))
230                                         return -EINVAL;
231                                 needs_mask = 1;
232                                 break;
233 
234                         case ACL_GROUP_OBJ:
235                                 if (state == ACL_USER) {
236                                         state = ACL_GROUP;
237                                         break;
238                                 }
239                                 return -EINVAL;
240 
241                         case ACL_GROUP:
242                                 if (state != ACL_GROUP)
243                                         return -EINVAL;
244                                 if (!kgid_has_mapping(user_ns, pa->e_gid))
245                                         return -EINVAL;
246                                 needs_mask = 1;
247                                 break;
248 
249                         case ACL_MASK:
250                                 if (state != ACL_GROUP)
251                                         return -EINVAL;
252                                 state = ACL_OTHER;
253                                 break;
254 
255                         case ACL_OTHER:
256                                 if (state == ACL_OTHER ||
257                                     (state == ACL_GROUP && !needs_mask)) {
258                                         state = 0;
259                                         break;
260                                 }
261                                 return -EINVAL;
262 
263                         default:
264                                 return -EINVAL;
265                 }
266         }
267         if (state == 0)
268                 return 0;
269         return -EINVAL;
270 }
271 EXPORT_SYMBOL(posix_acl_valid);
272 
273 /*
274  * Returns 0 if the acl can be exactly represented in the traditional
275  * file mode permission bits, or else 1. Returns -E... on error.
276  */
277 int
278 posix_acl_equiv_mode(const struct posix_acl *acl, umode_t *mode_p)
279 {
280         const struct posix_acl_entry *pa, *pe;
281         umode_t mode = 0;
282         int not_equiv = 0;
283 
284         /*
285          * A null ACL can always be presented as mode bits.
286          */
287         if (!acl)
288                 return 0;
289 
290         FOREACH_ACL_ENTRY(pa, acl, pe) {
291                 switch (pa->e_tag) {
292                         case ACL_USER_OBJ:
293                                 mode |= (pa->e_perm & S_IRWXO) << 6;
294                                 break;
295                         case ACL_GROUP_OBJ:
296                                 mode |= (pa->e_perm & S_IRWXO) << 3;
297                                 break;
298                         case ACL_OTHER:
299                                 mode |= pa->e_perm & S_IRWXO;
300                                 break;
301                         case ACL_MASK:
302                                 mode = (mode & ~S_IRWXG) |
303                                        ((pa->e_perm & S_IRWXO) << 3);
304                                 not_equiv = 1;
305                                 break;
306                         case ACL_USER:
307                         case ACL_GROUP:
308                                 not_equiv = 1;
309                                 break;
310                         default:
311                                 return -EINVAL;
312                 }
313         }
314         if (mode_p)
315                 *mode_p = (*mode_p & ~S_IRWXUGO) | mode;
316         return not_equiv;
317 }
318 EXPORT_SYMBOL(posix_acl_equiv_mode);
319 
320 /*
321  * Create an ACL representing the file mode permission bits of an inode.
322  */
323 struct posix_acl *
324 posix_acl_from_mode(umode_t mode, gfp_t flags)
325 {
326         struct posix_acl *acl = posix_acl_alloc(3, flags);
327         if (!acl)
328                 return ERR_PTR(-ENOMEM);
329 
330         acl->a_entries[0].e_tag  = ACL_USER_OBJ;
331         acl->a_entries[0].e_perm = (mode & S_IRWXU) >> 6;
332 
333         acl->a_entries[1].e_tag  = ACL_GROUP_OBJ;
334         acl->a_entries[1].e_perm = (mode & S_IRWXG) >> 3;
335 
336         acl->a_entries[2].e_tag  = ACL_OTHER;
337         acl->a_entries[2].e_perm = (mode & S_IRWXO);
338         return acl;
339 }
340 EXPORT_SYMBOL(posix_acl_from_mode);
341 
342 /*
343  * Return 0 if current is granted want access to the inode
344  * by the acl. Returns -E... otherwise.
345  */
346 int
347 posix_acl_permission(struct inode *inode, const struct posix_acl *acl, int want)
348 {
349         const struct posix_acl_entry *pa, *pe, *mask_obj;
350         int found = 0;
351 
352         want &= MAY_READ | MAY_WRITE | MAY_EXEC | MAY_NOT_BLOCK;
353 
354         FOREACH_ACL_ENTRY(pa, acl, pe) {
355                 switch(pa->e_tag) {
356                         case ACL_USER_OBJ:
357                                 /* (May have been checked already) */
358                                 if (uid_eq(inode->i_uid, current_fsuid()))
359                                         goto check_perm;
360                                 break;
361                         case ACL_USER:
362                                 if (uid_eq(pa->e_uid, current_fsuid()))
363                                         goto mask;
364                                 break;
365                         case ACL_GROUP_OBJ:
366                                 if (in_group_p(inode->i_gid)) {
367                                         found = 1;
368                                         if ((pa->e_perm & want) == want)
369                                                 goto mask;
370                                 }
371                                 break;
372                         case ACL_GROUP:
373                                 if (in_group_p(pa->e_gid)) {
374                                         found = 1;
375                                         if ((pa->e_perm & want) == want)
376                                                 goto mask;
377                                 }
378                                 break;
379                         case ACL_MASK:
380                                 break;
381                         case ACL_OTHER:
382                                 if (found)
383                                         return -EACCES;
384                                 else
385                                         goto check_perm;
386                         default:
387                                 return -EIO;
388                 }
389         }
390         return -EIO;
391 
392 mask:
393         for (mask_obj = pa+1; mask_obj != pe; mask_obj++) {
394                 if (mask_obj->e_tag == ACL_MASK) {
395                         if ((pa->e_perm & mask_obj->e_perm & want) == want)
396                                 return 0;
397                         return -EACCES;
398                 }
399         }
400 
401 check_perm:
402         if ((pa->e_perm & want) == want)
403                 return 0;
404         return -EACCES;
405 }
406 
407 /*
408  * Modify acl when creating a new inode. The caller must ensure the acl is
409  * only referenced once.
410  *
411  * mode_p initially must contain the mode parameter to the open() / creat()
412  * system calls. All permissions that are not granted by the acl are removed.
413  * The permissions in the acl are changed to reflect the mode_p parameter.
414  */
415 static int posix_acl_create_masq(struct posix_acl *acl, umode_t *mode_p)
416 {
417         struct posix_acl_entry *pa, *pe;
418         struct posix_acl_entry *group_obj = NULL, *mask_obj = NULL;
419         umode_t mode = *mode_p;
420         int not_equiv = 0;
421 
422         /* assert(atomic_read(acl->a_refcount) == 1); */
423 
424         FOREACH_ACL_ENTRY(pa, acl, pe) {
425                 switch(pa->e_tag) {
426                         case ACL_USER_OBJ:
427                                 pa->e_perm &= (mode >> 6) | ~S_IRWXO;
428                                 mode &= (pa->e_perm << 6) | ~S_IRWXU;
429                                 break;
430 
431                         case ACL_USER:
432                         case ACL_GROUP:
433                                 not_equiv = 1;
434                                 break;
435 
436                         case ACL_GROUP_OBJ:
437                                 group_obj = pa;
438                                 break;
439 
440                         case ACL_OTHER:
441                                 pa->e_perm &= mode | ~S_IRWXO;
442                                 mode &= pa->e_perm | ~S_IRWXO;
443                                 break;
444 
445                         case ACL_MASK:
446                                 mask_obj = pa;
447                                 not_equiv = 1;
448                                 break;
449 
450                         default:
451                                 return -EIO;
452                 }
453         }
454 
455         if (mask_obj) {
456                 mask_obj->e_perm &= (mode >> 3) | ~S_IRWXO;
457                 mode &= (mask_obj->e_perm << 3) | ~S_IRWXG;
458         } else {
459                 if (!group_obj)
460                         return -EIO;
461                 group_obj->e_perm &= (mode >> 3) | ~S_IRWXO;
462                 mode &= (group_obj->e_perm << 3) | ~S_IRWXG;
463         }
464 
465         *mode_p = (*mode_p & ~S_IRWXUGO) | mode;
466         return not_equiv;
467 }
468 
469 /*
470  * Modify the ACL for the chmod syscall.
471  */
472 static int __posix_acl_chmod_masq(struct posix_acl *acl, umode_t mode)
473 {
474         struct posix_acl_entry *group_obj = NULL, *mask_obj = NULL;
475         struct posix_acl_entry *pa, *pe;
476 
477         /* assert(atomic_read(acl->a_refcount) == 1); */
478 
479         FOREACH_ACL_ENTRY(pa, acl, pe) {
480                 switch(pa->e_tag) {
481                         case ACL_USER_OBJ:
482                                 pa->e_perm = (mode & S_IRWXU) >> 6;
483                                 break;
484 
485                         case ACL_USER:
486                         case ACL_GROUP:
487                                 break;
488 
489                         case ACL_GROUP_OBJ:
490                                 group_obj = pa;
491                                 break;
492 
493                         case ACL_MASK:
494                                 mask_obj = pa;
495                                 break;
496 
497                         case ACL_OTHER:
498                                 pa->e_perm = (mode & S_IRWXO);
499                                 break;
500 
501                         default:
502                                 return -EIO;
503                 }
504         }
505 
506         if (mask_obj) {
507                 mask_obj->e_perm = (mode & S_IRWXG) >> 3;
508         } else {
509                 if (!group_obj)
510                         return -EIO;
511                 group_obj->e_perm = (mode & S_IRWXG) >> 3;
512         }
513 
514         return 0;
515 }
516 
517 int
518 __posix_acl_create(struct posix_acl **acl, gfp_t gfp, umode_t *mode_p)
519 {
520         struct posix_acl *clone = posix_acl_clone(*acl, gfp);
521         int err = -ENOMEM;
522         if (clone) {
523                 err = posix_acl_create_masq(clone, mode_p);
524                 if (err < 0) {
525                         posix_acl_release(clone);
526                         clone = NULL;
527                 }
528         }
529         posix_acl_release(*acl);
530         *acl = clone;
531         return err;
532 }
533 EXPORT_SYMBOL(__posix_acl_create);
534 
535 int
536 __posix_acl_chmod(struct posix_acl **acl, gfp_t gfp, umode_t mode)
537 {
538         struct posix_acl *clone = posix_acl_clone(*acl, gfp);
539         int err = -ENOMEM;
540         if (clone) {
541                 err = __posix_acl_chmod_masq(clone, mode);
542                 if (err) {
543                         posix_acl_release(clone);
544                         clone = NULL;
545                 }
546         }
547         posix_acl_release(*acl);
548         *acl = clone;
549         return err;
550 }
551 EXPORT_SYMBOL(__posix_acl_chmod);
552 
553 int
554 posix_acl_chmod(struct inode *inode, umode_t mode)
555 {
556         struct posix_acl *acl;
557         int ret = 0;
558 
559         if (!IS_POSIXACL(inode))
560                 return 0;
561         if (!inode->i_op->set_acl)
562                 return -EOPNOTSUPP;
563 
564         acl = get_acl(inode, ACL_TYPE_ACCESS);
565         if (IS_ERR_OR_NULL(acl)) {
566                 if (acl == ERR_PTR(-EOPNOTSUPP))
567                         return 0;
568                 return PTR_ERR(acl);
569         }
570 
571         ret = __posix_acl_chmod(&acl, GFP_KERNEL, mode);
572         if (ret)
573                 return ret;
574         ret = inode->i_op->set_acl(inode, acl, ACL_TYPE_ACCESS);
575         posix_acl_release(acl);
576         return ret;
577 }
578 EXPORT_SYMBOL(posix_acl_chmod);
579 
580 int
581 posix_acl_create(struct inode *dir, umode_t *mode,
582                 struct posix_acl **default_acl, struct posix_acl **acl)
583 {
584         struct posix_acl *p;
585         struct posix_acl *clone;
586         int ret;
587 
588         *acl = NULL;
589         *default_acl = NULL;
590 
591         if (S_ISLNK(*mode) || !IS_POSIXACL(dir))
592                 return 0;
593 
594         p = get_acl(dir, ACL_TYPE_DEFAULT);
595         if (!p || p == ERR_PTR(-EOPNOTSUPP)) {
596                 *mode &= ~current_umask();
597                 return 0;
598         }
599         if (IS_ERR(p))
600                 return PTR_ERR(p);
601 
602         ret = -ENOMEM;
603         clone = posix_acl_clone(p, GFP_NOFS);
604         if (!clone)
605                 goto err_release;
606 
607         ret = posix_acl_create_masq(clone, mode);
608         if (ret < 0)
609                 goto err_release_clone;
610 
611         if (ret == 0)
612                 posix_acl_release(clone);
613         else
614                 *acl = clone;
615 
616         if (!S_ISDIR(*mode))
617                 posix_acl_release(p);
618         else
619                 *default_acl = p;
620 
621         return 0;
622 
623 err_release_clone:
624         posix_acl_release(clone);
625 err_release:
626         posix_acl_release(p);
627         return ret;
628 }
629 EXPORT_SYMBOL_GPL(posix_acl_create);
630 
631 /**
632  * posix_acl_update_mode  -  update mode in set_acl
633  *
634  * Update the file mode when setting an ACL: compute the new file permission
635  * bits based on the ACL.  In addition, if the ACL is equivalent to the new
636  * file mode, set *acl to NULL to indicate that no ACL should be set.
637  *
638  * As with chmod, clear the setgit bit if the caller is not in the owning group
639  * or capable of CAP_FSETID (see inode_change_ok).
640  *
641  * Called from set_acl inode operations.
642  */
643 int posix_acl_update_mode(struct inode *inode, umode_t *mode_p,
644                           struct posix_acl **acl)
645 {
646         umode_t mode = inode->i_mode;
647         int error;
648 
649         error = posix_acl_equiv_mode(*acl, &mode);
650         if (error < 0)
651                 return error;
652         if (error == 0)
653                 *acl = NULL;
654         if (!in_group_p(inode->i_gid) &&
655             !capable_wrt_inode_uidgid(inode, CAP_FSETID))
656                 mode &= ~S_ISGID;
657         *mode_p = mode;
658         return 0;
659 }
660 EXPORT_SYMBOL(posix_acl_update_mode);
661 
662 /*
663  * Fix up the uids and gids in posix acl extended attributes in place.
664  */
665 static void posix_acl_fix_xattr_userns(
666         struct user_namespace *to, struct user_namespace *from,
667         void *value, size_t size)
668 {
669         struct posix_acl_xattr_header *header = value;
670         struct posix_acl_xattr_entry *entry = (void *)(header + 1), *end;
671         int count;
672         kuid_t uid;
673         kgid_t gid;
674 
675         if (!value)
676                 return;
677         if (size < sizeof(struct posix_acl_xattr_header))
678                 return;
679         if (header->a_version != cpu_to_le32(POSIX_ACL_XATTR_VERSION))
680                 return;
681 
682         count = posix_acl_xattr_count(size);
683         if (count < 0)
684                 return;
685         if (count == 0)
686                 return;
687 
688         for (end = entry + count; entry != end; entry++) {
689                 switch(le16_to_cpu(entry->e_tag)) {
690                 case ACL_USER:
691                         uid = make_kuid(from, le32_to_cpu(entry->e_id));
692                         entry->e_id = cpu_to_le32(from_kuid(to, uid));
693                         break;
694                 case ACL_GROUP:
695                         gid = make_kgid(from, le32_to_cpu(entry->e_id));
696                         entry->e_id = cpu_to_le32(from_kgid(to, gid));
697                         break;
698                 default:
699                         break;
700                 }
701         }
702 }
703 
704 void posix_acl_fix_xattr_from_user(void *value, size_t size)
705 {
706         struct user_namespace *user_ns = current_user_ns();
707         if (user_ns == &init_user_ns)
708                 return;
709         posix_acl_fix_xattr_userns(&init_user_ns, user_ns, value, size);
710 }
711 
712 void posix_acl_fix_xattr_to_user(void *value, size_t size)
713 {
714         struct user_namespace *user_ns = current_user_ns();
715         if (user_ns == &init_user_ns)
716                 return;
717         posix_acl_fix_xattr_userns(user_ns, &init_user_ns, value, size);
718 }
719 
720 /*
721  * Convert from extended attribute to in-memory representation.
722  */
723 struct posix_acl *
724 posix_acl_from_xattr(struct user_namespace *user_ns,
725                      const void *value, size_t size)
726 {
727         const struct posix_acl_xattr_header *header = value;
728         const struct posix_acl_xattr_entry *entry = (const void *)(header + 1), *end;
729         int count;
730         struct posix_acl *acl;
731         struct posix_acl_entry *acl_e;
732 
733         if (!value)
734                 return NULL;
735         if (size < sizeof(struct posix_acl_xattr_header))
736                  return ERR_PTR(-EINVAL);
737         if (header->a_version != cpu_to_le32(POSIX_ACL_XATTR_VERSION))
738                 return ERR_PTR(-EOPNOTSUPP);
739 
740         count = posix_acl_xattr_count(size);
741         if (count < 0)
742                 return ERR_PTR(-EINVAL);
743         if (count == 0)
744                 return NULL;
745         
746         acl = posix_acl_alloc(count, GFP_NOFS);
747         if (!acl)
748                 return ERR_PTR(-ENOMEM);
749         acl_e = acl->a_entries;
750         
751         for (end = entry + count; entry != end; acl_e++, entry++) {
752                 acl_e->e_tag  = le16_to_cpu(entry->e_tag);
753                 acl_e->e_perm = le16_to_cpu(entry->e_perm);
754 
755                 switch(acl_e->e_tag) {
756                         case ACL_USER_OBJ:
757                         case ACL_GROUP_OBJ:
758                         case ACL_MASK:
759                         case ACL_OTHER:
760                                 break;
761 
762                         case ACL_USER:
763                                 acl_e->e_uid =
764                                         make_kuid(user_ns,
765                                                   le32_to_cpu(entry->e_id));
766                                 if (!uid_valid(acl_e->e_uid))
767                                         goto fail;
768                                 break;
769                         case ACL_GROUP:
770                                 acl_e->e_gid =
771                                         make_kgid(user_ns,
772                                                   le32_to_cpu(entry->e_id));
773                                 if (!gid_valid(acl_e->e_gid))
774                                         goto fail;
775                                 break;
776 
777                         default:
778                                 goto fail;
779                 }
780         }
781         return acl;
782 
783 fail:
784         posix_acl_release(acl);
785         return ERR_PTR(-EINVAL);
786 }
787 EXPORT_SYMBOL (posix_acl_from_xattr);
788 
789 /*
790  * Convert from in-memory to extended attribute representation.
791  */
792 int
793 posix_acl_to_xattr(struct user_namespace *user_ns, const struct posix_acl *acl,
794                    void *buffer, size_t size)
795 {
796         struct posix_acl_xattr_header *ext_acl = buffer;
797         struct posix_acl_xattr_entry *ext_entry;
798         int real_size, n;
799 
800         real_size = posix_acl_xattr_size(acl->a_count);
801         if (!buffer)
802                 return real_size;
803         if (real_size > size)
804                 return -ERANGE;
805 
806         ext_entry = (void *)(ext_acl + 1);
807         ext_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
808 
809         for (n=0; n < acl->a_count; n++, ext_entry++) {
810                 const struct posix_acl_entry *acl_e = &acl->a_entries[n];
811                 ext_entry->e_tag  = cpu_to_le16(acl_e->e_tag);
812                 ext_entry->e_perm = cpu_to_le16(acl_e->e_perm);
813                 switch(acl_e->e_tag) {
814                 case ACL_USER:
815                         ext_entry->e_id =
816                                 cpu_to_le32(from_kuid(user_ns, acl_e->e_uid));
817                         break;
818                 case ACL_GROUP:
819                         ext_entry->e_id =
820                                 cpu_to_le32(from_kgid(user_ns, acl_e->e_gid));
821                         break;
822                 default:
823                         ext_entry->e_id = cpu_to_le32(ACL_UNDEFINED_ID);
824                         break;
825                 }
826         }
827         return real_size;
828 }
829 EXPORT_SYMBOL (posix_acl_to_xattr);
830 
831 static int
832 posix_acl_xattr_get(const struct xattr_handler *handler,
833                     struct dentry *unused, struct inode *inode,
834                     const char *name, void *value, size_t size)
835 {
836         struct posix_acl *acl;
837         int error;
838 
839         if (!IS_POSIXACL(inode))
840                 return -EOPNOTSUPP;
841         if (S_ISLNK(inode->i_mode))
842                 return -EOPNOTSUPP;
843 
844         acl = get_acl(inode, handler->flags);
845         if (IS_ERR(acl))
846                 return PTR_ERR(acl);
847         if (acl == NULL)
848                 return -ENODATA;
849 
850         error = posix_acl_to_xattr(&init_user_ns, acl, value, size);
851         posix_acl_release(acl);
852 
853         return error;
854 }
855 
856 int
857 set_posix_acl(struct inode *inode, int type, struct posix_acl *acl)
858 {
859         if (!IS_POSIXACL(inode))
860                 return -EOPNOTSUPP;
861         if (!inode->i_op->set_acl)
862                 return -EOPNOTSUPP;
863 
864         if (type == ACL_TYPE_DEFAULT && !S_ISDIR(inode->i_mode))
865                 return acl ? -EACCES : 0;
866         if (!inode_owner_or_capable(inode))
867                 return -EPERM;
868 
869         if (acl) {
870                 int ret = posix_acl_valid(inode->i_sb->s_user_ns, acl);
871                 if (ret)
872                         return ret;
873         }
874         return inode->i_op->set_acl(inode, acl, type);
875 }
876 EXPORT_SYMBOL(set_posix_acl);
877 
878 static int
879 posix_acl_xattr_set(const struct xattr_handler *handler,
880                     struct dentry *unused, struct inode *inode,
881                     const char *name, const void *value,
882                     size_t size, int flags)
883 {
884         struct posix_acl *acl = NULL;
885         int ret;
886 
887         if (value) {
888                 acl = posix_acl_from_xattr(&init_user_ns, value, size);
889                 if (IS_ERR(acl))
890                         return PTR_ERR(acl);
891         }
892         ret = set_posix_acl(inode, handler->flags, acl);
893         posix_acl_release(acl);
894         return ret;
895 }
896 
897 static bool
898 posix_acl_xattr_list(struct dentry *dentry)
899 {
900         return IS_POSIXACL(d_backing_inode(dentry));
901 }
902 
903 const struct xattr_handler posix_acl_access_xattr_handler = {
904         .name = XATTR_NAME_POSIX_ACL_ACCESS,
905         .flags = ACL_TYPE_ACCESS,
906         .list = posix_acl_xattr_list,
907         .get = posix_acl_xattr_get,
908         .set = posix_acl_xattr_set,
909 };
910 EXPORT_SYMBOL_GPL(posix_acl_access_xattr_handler);
911 
912 const struct xattr_handler posix_acl_default_xattr_handler = {
913         .name = XATTR_NAME_POSIX_ACL_DEFAULT,
914         .flags = ACL_TYPE_DEFAULT,
915         .list = posix_acl_xattr_list,
916         .get = posix_acl_xattr_get,
917         .set = posix_acl_xattr_set,
918 };
919 EXPORT_SYMBOL_GPL(posix_acl_default_xattr_handler);
920 
921 int simple_set_acl(struct inode *inode, struct posix_acl *acl, int type)
922 {
923         int error;
924 
925         if (type == ACL_TYPE_ACCESS) {
926                 error = posix_acl_update_mode(inode,
927                                 &inode->i_mode, &acl);
928                 if (error)
929                         return error;
930         }
931 
932         inode->i_ctime = current_time(inode);
933         set_cached_acl(inode, type, acl);
934         return 0;
935 }
936 
937 int simple_acl_create(struct inode *dir, struct inode *inode)
938 {
939         struct posix_acl *default_acl, *acl;
940         int error;
941 
942         error = posix_acl_create(dir, &inode->i_mode, &default_acl, &acl);
943         if (error)
944                 return error;
945 
946         set_cached_acl(inode, ACL_TYPE_DEFAULT, default_acl);
947         set_cached_acl(inode, ACL_TYPE_ACCESS, acl);
948 
949         if (default_acl)
950                 posix_acl_release(default_acl);
951         if (acl)
952                 posix_acl_release(acl);
953         return 0;
954 }
955 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp