diff options
author | Christoph Hellwig <hch@infradead.org> | 2013-12-20 08:16:37 -0500 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2014-01-25 23:58:16 -0500 |
commit | 5c8ebd57b6a51daf53f75b7a16c45090a98a91a4 (patch) | |
tree | 02e3d3b8f707f84effe15df3dfc0043481010390 /fs/posix_acl.c | |
parent | 9dad943ae7d4a01da6bb18e1a157ab1bfe6186cd (diff) |
fs: merge xattr_acl.c into posix_acl.c
Signed-off-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs/posix_acl.c')
-rw-r--r-- | fs/posix_acl.c | 180 |
1 files changed, 173 insertions, 7 deletions
diff --git a/fs/posix_acl.c b/fs/posix_acl.c index 8bd2135b7f82..359d70b0e947 100644 --- a/fs/posix_acl.c +++ b/fs/posix_acl.c | |||
@@ -1,10 +1,8 @@ | |||
1 | /* | 1 | /* |
2 | * linux/fs/posix_acl.c | 2 | * Copyright (C) 2002,2003 by Andreas Gruenbacher <a.gruenbacher@computer.org> |
3 | * | 3 | * |
4 | * Copyright (C) 2002 by Andreas Gruenbacher <a.gruenbacher@computer.org> | 4 | * Fixes from William Schumacher incorporated on 15 March 2001. |
5 | * | 5 | * (Reported by Charles Bertsch, <CBertsch@microtest.com>). |
6 | * Fixes from William Schumacher incorporated on 15 March 2001. | ||
7 | * (Reported by Charles Bertsch, <CBertsch@microtest.com>). | ||
8 | */ | 6 | */ |
9 | 7 | ||
10 | /* | 8 | /* |
@@ -18,9 +16,9 @@ | |||
18 | #include <linux/fs.h> | 16 | #include <linux/fs.h> |
19 | #include <linux/sched.h> | 17 | #include <linux/sched.h> |
20 | #include <linux/posix_acl.h> | 18 | #include <linux/posix_acl.h> |
19 | #include <linux/posix_acl_xattr.h> | ||
21 | #include <linux/export.h> | 20 | #include <linux/export.h> |
22 | 21 | #include <linux/user_namespace.h> | |
23 | #include <linux/errno.h> | ||
24 | 22 | ||
25 | EXPORT_SYMBOL(posix_acl_init); | 23 | EXPORT_SYMBOL(posix_acl_init); |
26 | EXPORT_SYMBOL(posix_acl_alloc); | 24 | EXPORT_SYMBOL(posix_acl_alloc); |
@@ -418,3 +416,171 @@ posix_acl_chmod(struct posix_acl **acl, gfp_t gfp, umode_t mode) | |||
418 | return err; | 416 | return err; |
419 | } | 417 | } |
420 | EXPORT_SYMBOL(posix_acl_chmod); | 418 | EXPORT_SYMBOL(posix_acl_chmod); |
419 | |||
420 | /* | ||
421 | * Fix up the uids and gids in posix acl extended attributes in place. | ||
422 | */ | ||
423 | static void posix_acl_fix_xattr_userns( | ||
424 | struct user_namespace *to, struct user_namespace *from, | ||
425 | void *value, size_t size) | ||
426 | { | ||
427 | posix_acl_xattr_header *header = (posix_acl_xattr_header *)value; | ||
428 | posix_acl_xattr_entry *entry = (posix_acl_xattr_entry *)(header+1), *end; | ||
429 | int count; | ||
430 | kuid_t uid; | ||
431 | kgid_t gid; | ||
432 | |||
433 | if (!value) | ||
434 | return; | ||
435 | if (size < sizeof(posix_acl_xattr_header)) | ||
436 | return; | ||
437 | if (header->a_version != cpu_to_le32(POSIX_ACL_XATTR_VERSION)) | ||
438 | return; | ||
439 | |||
440 | count = posix_acl_xattr_count(size); | ||
441 | if (count < 0) | ||
442 | return; | ||
443 | if (count == 0) | ||
444 | return; | ||
445 | |||
446 | for (end = entry + count; entry != end; entry++) { | ||
447 | switch(le16_to_cpu(entry->e_tag)) { | ||
448 | case ACL_USER: | ||
449 | uid = make_kuid(from, le32_to_cpu(entry->e_id)); | ||
450 | entry->e_id = cpu_to_le32(from_kuid(to, uid)); | ||
451 | break; | ||
452 | case ACL_GROUP: | ||
453 | gid = make_kgid(from, le32_to_cpu(entry->e_id)); | ||
454 | entry->e_id = cpu_to_le32(from_kgid(to, gid)); | ||
455 | break; | ||
456 | default: | ||
457 | break; | ||
458 | } | ||
459 | } | ||
460 | } | ||
461 | |||
462 | void posix_acl_fix_xattr_from_user(void *value, size_t size) | ||
463 | { | ||
464 | struct user_namespace *user_ns = current_user_ns(); | ||
465 | if (user_ns == &init_user_ns) | ||
466 | return; | ||
467 | posix_acl_fix_xattr_userns(&init_user_ns, user_ns, value, size); | ||
468 | } | ||
469 | |||
470 | void posix_acl_fix_xattr_to_user(void *value, size_t size) | ||
471 | { | ||
472 | struct user_namespace *user_ns = current_user_ns(); | ||
473 | if (user_ns == &init_user_ns) | ||
474 | return; | ||
475 | posix_acl_fix_xattr_userns(user_ns, &init_user_ns, value, size); | ||
476 | } | ||
477 | |||
478 | /* | ||
479 | * Convert from extended attribute to in-memory representation. | ||
480 | */ | ||
481 | struct posix_acl * | ||
482 | posix_acl_from_xattr(struct user_namespace *user_ns, | ||
483 | const void *value, size_t size) | ||
484 | { | ||
485 | posix_acl_xattr_header *header = (posix_acl_xattr_header *)value; | ||
486 | posix_acl_xattr_entry *entry = (posix_acl_xattr_entry *)(header+1), *end; | ||
487 | int count; | ||
488 | struct posix_acl *acl; | ||
489 | struct posix_acl_entry *acl_e; | ||
490 | |||
491 | if (!value) | ||
492 | return NULL; | ||
493 | if (size < sizeof(posix_acl_xattr_header)) | ||
494 | return ERR_PTR(-EINVAL); | ||
495 | if (header->a_version != cpu_to_le32(POSIX_ACL_XATTR_VERSION)) | ||
496 | return ERR_PTR(-EOPNOTSUPP); | ||
497 | |||
498 | count = posix_acl_xattr_count(size); | ||
499 | if (count < 0) | ||
500 | return ERR_PTR(-EINVAL); | ||
501 | if (count == 0) | ||
502 | return NULL; | ||
503 | |||
504 | acl = posix_acl_alloc(count, GFP_NOFS); | ||
505 | if (!acl) | ||
506 | return ERR_PTR(-ENOMEM); | ||
507 | acl_e = acl->a_entries; | ||
508 | |||
509 | for (end = entry + count; entry != end; acl_e++, entry++) { | ||
510 | acl_e->e_tag = le16_to_cpu(entry->e_tag); | ||
511 | acl_e->e_perm = le16_to_cpu(entry->e_perm); | ||
512 | |||
513 | switch(acl_e->e_tag) { | ||
514 | case ACL_USER_OBJ: | ||
515 | case ACL_GROUP_OBJ: | ||
516 | case ACL_MASK: | ||
517 | case ACL_OTHER: | ||
518 | break; | ||
519 | |||
520 | case ACL_USER: | ||
521 | acl_e->e_uid = | ||
522 | make_kuid(user_ns, | ||
523 | le32_to_cpu(entry->e_id)); | ||
524 | if (!uid_valid(acl_e->e_uid)) | ||
525 | goto fail; | ||
526 | break; | ||
527 | case ACL_GROUP: | ||
528 | acl_e->e_gid = | ||
529 | make_kgid(user_ns, | ||
530 | le32_to_cpu(entry->e_id)); | ||
531 | if (!gid_valid(acl_e->e_gid)) | ||
532 | goto fail; | ||
533 | break; | ||
534 | |||
535 | default: | ||
536 | goto fail; | ||
537 | } | ||
538 | } | ||
539 | return acl; | ||
540 | |||
541 | fail: | ||
542 | posix_acl_release(acl); | ||
543 | return ERR_PTR(-EINVAL); | ||
544 | } | ||
545 | EXPORT_SYMBOL (posix_acl_from_xattr); | ||
546 | |||
547 | /* | ||
548 | * Convert from in-memory to extended attribute representation. | ||
549 | */ | ||
550 | int | ||
551 | posix_acl_to_xattr(struct user_namespace *user_ns, const struct posix_acl *acl, | ||
552 | void *buffer, size_t size) | ||
553 | { | ||
554 | posix_acl_xattr_header *ext_acl = (posix_acl_xattr_header *)buffer; | ||
555 | posix_acl_xattr_entry *ext_entry = ext_acl->a_entries; | ||
556 | int real_size, n; | ||
557 | |||
558 | real_size = posix_acl_xattr_size(acl->a_count); | ||
559 | if (!buffer) | ||
560 | return real_size; | ||
561 | if (real_size > size) | ||
562 | return -ERANGE; | ||
563 | |||
564 | ext_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION); | ||
565 | |||
566 | for (n=0; n < acl->a_count; n++, ext_entry++) { | ||
567 | const struct posix_acl_entry *acl_e = &acl->a_entries[n]; | ||
568 | ext_entry->e_tag = cpu_to_le16(acl_e->e_tag); | ||
569 | ext_entry->e_perm = cpu_to_le16(acl_e->e_perm); | ||
570 | switch(acl_e->e_tag) { | ||
571 | case ACL_USER: | ||
572 | ext_entry->e_id = | ||
573 | cpu_to_le32(from_kuid(user_ns, acl_e->e_uid)); | ||
574 | break; | ||
575 | case ACL_GROUP: | ||
576 | ext_entry->e_id = | ||
577 | cpu_to_le32(from_kgid(user_ns, acl_e->e_gid)); | ||
578 | break; | ||
579 | default: | ||
580 | ext_entry->e_id = cpu_to_le32(ACL_UNDEFINED_ID); | ||
581 | break; | ||
582 | } | ||
583 | } | ||
584 | return real_size; | ||
585 | } | ||
586 | EXPORT_SYMBOL (posix_acl_to_xattr); | ||