1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright (C) 2007 Red Hat. All rights reserved. 4 */ 5 6 #include <linux/fs.h> 7 #include <linux/string.h> 8 #include <linux/xattr.h> 9 #include <linux/posix_acl_xattr.h> 10 #include <linux/posix_acl.h> 11 #include <linux/sched.h> 12 #include <linux/sched/mm.h> 13 #include <linux/slab.h> 14 15 #include "ctree.h" 16 #include "btrfs_inode.h" 17 #include "xattr.h" 18 19 struct posix_acl *btrfs_get_acl(struct inode *inode, int type) 20 { 21 int size; 22 const char *name; 23 char *value = NULL; 24 struct posix_acl *acl; 25 26 switch (type) { 27 case ACL_TYPE_ACCESS: 28 name = XATTR_NAME_POSIX_ACL_ACCESS; 29 break; 30 case ACL_TYPE_DEFAULT: 31 name = XATTR_NAME_POSIX_ACL_DEFAULT; 32 break; 33 default: 34 return ERR_PTR(-EINVAL); 35 } 36 37 size = btrfs_getxattr(inode, name, NULL, 0); 38 if (size > 0) { 39 value = kzalloc(size, GFP_KERNEL); 40 if (!value) 41 return ERR_PTR(-ENOMEM); 42 size = btrfs_getxattr(inode, name, value, size); 43 } 44 if (size > 0) 45 acl = posix_acl_from_xattr(&init_user_ns, value, size); 46 else if (size == -ENODATA || size == 0) 47 acl = NULL; 48 else 49 acl = ERR_PTR(size); 50 kfree(value); 51 52 return acl; 53 } 54 55 static int __btrfs_set_acl(struct btrfs_trans_handle *trans, 56 struct inode *inode, struct posix_acl *acl, int type) 57 { 58 int ret, size = 0; 59 const char *name; 60 char *value = NULL; 61 62 switch (type) { 63 case ACL_TYPE_ACCESS: 64 name = XATTR_NAME_POSIX_ACL_ACCESS; 65 break; 66 case ACL_TYPE_DEFAULT: 67 if (!S_ISDIR(inode->i_mode)) 68 return acl ? -EINVAL : 0; 69 name = XATTR_NAME_POSIX_ACL_DEFAULT; 70 break; 71 default: 72 return -EINVAL; 73 } 74 75 if (acl) { 76 unsigned int nofs_flag; 77 78 size = posix_acl_xattr_size(acl->a_count); 79 /* 80 * We're holding a transaction handle, so use a NOFS memory 81 * allocation context to avoid deadlock if reclaim happens. 82 */ 83 nofs_flag = memalloc_nofs_save(); 84 value = kmalloc(size, GFP_KERNEL); 85 memalloc_nofs_restore(nofs_flag); 86 if (!value) { 87 ret = -ENOMEM; 88 goto out; 89 } 90 91 ret = posix_acl_to_xattr(&init_user_ns, acl, value, size); 92 if (ret < 0) 93 goto out; 94 } 95 96 if (trans) 97 ret = btrfs_setxattr(trans, inode, name, value, size, 0); 98 else 99 ret = btrfs_setxattr_trans(inode, name, value, size, 0); 100 101 out: 102 kfree(value); 103 104 if (!ret) 105 set_cached_acl(inode, type, acl); 106 107 return ret; 108 } 109 110 int btrfs_set_acl(struct user_namespace *mnt_userns, struct inode *inode, 111 struct posix_acl *acl, int type) 112 { 113 int ret; 114 umode_t old_mode = inode->i_mode; 115 116 if (type == ACL_TYPE_ACCESS && acl) { 117 ret = posix_acl_update_mode(&init_user_ns, inode, 118 &inode->i_mode, &acl); 119 if (ret) 120 return ret; 121 } 122 ret = __btrfs_set_acl(NULL, inode, acl, type); 123 if (ret) 124 inode->i_mode = old_mode; 125 return ret; 126 } 127 128 int btrfs_init_acl(struct btrfs_trans_handle *trans, 129 struct inode *inode, struct inode *dir) 130 { 131 struct posix_acl *default_acl, *acl; 132 int ret = 0; 133 134 /* this happens with subvols */ 135 if (!dir) 136 return 0; 137 138 ret = posix_acl_create(dir, &inode->i_mode, &default_acl, &acl); 139 if (ret) 140 return ret; 141 142 if (default_acl) { 143 ret = __btrfs_set_acl(trans, inode, default_acl, 144 ACL_TYPE_DEFAULT); 145 posix_acl_release(default_acl); 146 } 147 148 if (acl) { 149 if (!ret) 150 ret = __btrfs_set_acl(trans, inode, acl, 151 ACL_TYPE_ACCESS); 152 posix_acl_release(acl); 153 } 154 155 if (!default_acl && !acl) 156 cache_no_acl(inode); 157 return ret; 158 } 159