|
17 | 17 | #include <linux/sched.h>
|
18 | 18 | #include <linux/posix_acl.h>
|
19 | 19 | #include <linux/posix_acl_xattr.h>
|
| 20 | +#include <linux/xattr.h> |
20 | 21 | #include <linux/export.h>
|
21 | 22 | #include <linux/user_namespace.h>
|
22 | 23 |
|
@@ -611,3 +612,104 @@ posix_acl_to_xattr(struct user_namespace *user_ns, const struct posix_acl *acl,
|
611 | 612 | return real_size;
|
612 | 613 | }
|
613 | 614 | EXPORT_SYMBOL (posix_acl_to_xattr);
|
| 615 | + |
| 616 | +static int |
| 617 | +posix_acl_xattr_get(struct dentry *dentry, const char *name, |
| 618 | + void *value, size_t size, int type) |
| 619 | +{ |
| 620 | + struct posix_acl *acl; |
| 621 | + int error; |
| 622 | + |
| 623 | + if (!IS_POSIXACL(dentry->d_inode)) |
| 624 | + return -EOPNOTSUPP; |
| 625 | + if (S_ISLNK(dentry->d_inode->i_mode)) |
| 626 | + return -EOPNOTSUPP; |
| 627 | + |
| 628 | + acl = get_acl(dentry->d_inode, type); |
| 629 | + if (IS_ERR(acl)) |
| 630 | + return PTR_ERR(acl); |
| 631 | + if (acl == NULL) |
| 632 | + return -ENODATA; |
| 633 | + |
| 634 | + error = posix_acl_to_xattr(&init_user_ns, acl, value, size); |
| 635 | + posix_acl_release(acl); |
| 636 | + |
| 637 | + return error; |
| 638 | +} |
| 639 | + |
| 640 | +static int |
| 641 | +posix_acl_xattr_set(struct dentry *dentry, const char *name, |
| 642 | + const void *value, size_t size, int flags, int type) |
| 643 | +{ |
| 644 | + struct inode *inode = dentry->d_inode; |
| 645 | + struct posix_acl *acl = NULL; |
| 646 | + int ret; |
| 647 | + |
| 648 | + if (!IS_POSIXACL(inode)) |
| 649 | + return -EOPNOTSUPP; |
| 650 | + if (!inode->i_op->set_acl) |
| 651 | + return -EOPNOTSUPP; |
| 652 | + |
| 653 | + if (type == ACL_TYPE_DEFAULT && !S_ISDIR(inode->i_mode)) |
| 654 | + return value ? -EACCES : 0; |
| 655 | + if (!inode_owner_or_capable(inode)) |
| 656 | + return -EPERM; |
| 657 | + |
| 658 | + if (value) { |
| 659 | + acl = posix_acl_from_xattr(&init_user_ns, value, size); |
| 660 | + if (IS_ERR(acl)) |
| 661 | + return PTR_ERR(acl); |
| 662 | + |
| 663 | + if (acl) { |
| 664 | + ret = posix_acl_valid(acl); |
| 665 | + if (ret) |
| 666 | + goto out; |
| 667 | + } |
| 668 | + } |
| 669 | + |
| 670 | + ret = inode->i_op->set_acl(inode, acl, type); |
| 671 | +out: |
| 672 | + posix_acl_release(acl); |
| 673 | + return ret; |
| 674 | +} |
| 675 | + |
| 676 | +static size_t |
| 677 | +posix_acl_xattr_list(struct dentry *dentry, char *list, size_t list_size, |
| 678 | + const char *name, size_t name_len, int type) |
| 679 | +{ |
| 680 | + const char *xname; |
| 681 | + size_t size; |
| 682 | + |
| 683 | + if (!IS_POSIXACL(dentry->d_inode)) |
| 684 | + return -EOPNOTSUPP; |
| 685 | + if (S_ISLNK(dentry->d_inode->i_mode)) |
| 686 | + return -EOPNOTSUPP; |
| 687 | + |
| 688 | + if (type == ACL_TYPE_ACCESS) |
| 689 | + xname = POSIX_ACL_XATTR_ACCESS; |
| 690 | + else |
| 691 | + xname = POSIX_ACL_XATTR_DEFAULT; |
| 692 | + |
| 693 | + size = strlen(xname) + 1; |
| 694 | + if (list && size <= list_size) |
| 695 | + memcpy(list, xname, size); |
| 696 | + return size; |
| 697 | +} |
| 698 | + |
| 699 | +const struct xattr_handler posix_acl_access_xattr_handler = { |
| 700 | + .prefix = POSIX_ACL_XATTR_ACCESS, |
| 701 | + .flags = ACL_TYPE_ACCESS, |
| 702 | + .list = posix_acl_xattr_list, |
| 703 | + .get = posix_acl_xattr_get, |
| 704 | + .set = posix_acl_xattr_set, |
| 705 | +}; |
| 706 | +EXPORT_SYMBOL_GPL(posix_acl_access_xattr_handler); |
| 707 | + |
| 708 | +const struct xattr_handler posix_acl_default_xattr_handler = { |
| 709 | + .prefix = POSIX_ACL_XATTR_DEFAULT, |
| 710 | + .flags = ACL_TYPE_DEFAULT, |
| 711 | + .list = posix_acl_xattr_list, |
| 712 | + .get = posix_acl_xattr_get, |
| 713 | + .set = posix_acl_xattr_set, |
| 714 | +}; |
| 715 | +EXPORT_SYMBOL_GPL(posix_acl_default_xattr_handler); |
0 commit comments