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