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