1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright (C) 2008 Christoph Hellwig. 4 * Portions Copyright (C) 2000-2008 Silicon Graphics, Inc. 5 */ 6 7 #include "xfs.h" 8 #include "xfs_format.h" 9 #include "xfs_log_format.h" 10 #include "xfs_trans_resv.h" 11 #include "xfs_mount.h" 12 #include "xfs_da_format.h" 13 #include "xfs_inode.h" 14 #include "xfs_attr.h" 15 #include "xfs_attr_leaf.h" 16 #include "xfs_acl.h" 17 18 #include <linux/posix_acl_xattr.h> 19 #include <linux/xattr.h> 20 21 22 static int 23 xfs_xattr_get(const struct xattr_handler *handler, struct dentry *unused, 24 struct inode *inode, const char *name, void *value, size_t size) 25 { 26 int xflags = handler->flags; 27 struct xfs_inode *ip = XFS_I(inode); 28 int error, asize = size; 29 30 /* Convert Linux syscall to XFS internal ATTR flags */ 31 if (!size) { 32 xflags |= ATTR_KERNOVAL; 33 value = NULL; 34 } 35 36 error = xfs_attr_get(ip, (unsigned char *)name, value, &asize, xflags); 37 if (error) 38 return error; 39 return asize; 40 } 41 42 void 43 xfs_forget_acl( 44 struct inode *inode, 45 const char *name, 46 int xflags) 47 { 48 /* 49 * Invalidate any cached ACLs if the user has bypassed the ACL 50 * interface. We don't validate the content whatsoever so it is caller 51 * responsibility to provide data in valid format and ensure i_mode is 52 * consistent. 53 */ 54 if (xflags & ATTR_ROOT) { 55 #ifdef CONFIG_XFS_POSIX_ACL 56 if (!strcmp(name, SGI_ACL_FILE)) 57 forget_cached_acl(inode, ACL_TYPE_ACCESS); 58 else if (!strcmp(name, SGI_ACL_DEFAULT)) 59 forget_cached_acl(inode, ACL_TYPE_DEFAULT); 60 #endif 61 } 62 } 63 64 static int 65 xfs_xattr_set(const struct xattr_handler *handler, struct dentry *unused, 66 struct inode *inode, const char *name, const void *value, 67 size_t size, int flags) 68 { 69 int xflags = handler->flags; 70 struct xfs_inode *ip = XFS_I(inode); 71 int error; 72 73 /* Convert Linux syscall to XFS internal ATTR flags */ 74 if (flags & XATTR_CREATE) 75 xflags |= ATTR_CREATE; 76 if (flags & XATTR_REPLACE) 77 xflags |= ATTR_REPLACE; 78 79 if (!value) 80 return xfs_attr_remove(ip, (unsigned char *)name, xflags); 81 error = xfs_attr_set(ip, (unsigned char *)name, 82 (void *)value, size, xflags); 83 if (!error) 84 xfs_forget_acl(inode, name, xflags); 85 86 return error; 87 } 88 89 static const struct xattr_handler xfs_xattr_user_handler = { 90 .prefix = XATTR_USER_PREFIX, 91 .flags = 0, /* no flags implies user namespace */ 92 .get = xfs_xattr_get, 93 .set = xfs_xattr_set, 94 }; 95 96 static const struct xattr_handler xfs_xattr_trusted_handler = { 97 .prefix = XATTR_TRUSTED_PREFIX, 98 .flags = ATTR_ROOT, 99 .get = xfs_xattr_get, 100 .set = xfs_xattr_set, 101 }; 102 103 static const struct xattr_handler xfs_xattr_security_handler = { 104 .prefix = XATTR_SECURITY_PREFIX, 105 .flags = ATTR_SECURE, 106 .get = xfs_xattr_get, 107 .set = xfs_xattr_set, 108 }; 109 110 const struct xattr_handler *xfs_xattr_handlers[] = { 111 &xfs_xattr_user_handler, 112 &xfs_xattr_trusted_handler, 113 &xfs_xattr_security_handler, 114 #ifdef CONFIG_XFS_POSIX_ACL 115 &posix_acl_access_xattr_handler, 116 &posix_acl_default_xattr_handler, 117 #endif 118 NULL 119 }; 120 121 static void 122 __xfs_xattr_put_listent( 123 struct xfs_attr_list_context *context, 124 char *prefix, 125 int prefix_len, 126 unsigned char *name, 127 int namelen) 128 { 129 char *offset; 130 int arraytop; 131 132 if (context->count < 0 || context->seen_enough) 133 return; 134 135 if (!context->alist) 136 goto compute_size; 137 138 arraytop = context->count + prefix_len + namelen + 1; 139 if (arraytop > context->firstu) { 140 context->count = -1; /* insufficient space */ 141 context->seen_enough = 1; 142 return; 143 } 144 offset = (char *)context->alist + context->count; 145 strncpy(offset, prefix, prefix_len); 146 offset += prefix_len; 147 strncpy(offset, (char *)name, namelen); /* real name */ 148 offset += namelen; 149 *offset = '\0'; 150 151 compute_size: 152 context->count += prefix_len + namelen + 1; 153 return; 154 } 155 156 static void 157 xfs_xattr_put_listent( 158 struct xfs_attr_list_context *context, 159 int flags, 160 unsigned char *name, 161 int namelen, 162 int valuelen) 163 { 164 char *prefix; 165 int prefix_len; 166 167 ASSERT(context->count >= 0); 168 169 if (flags & XFS_ATTR_ROOT) { 170 #ifdef CONFIG_XFS_POSIX_ACL 171 if (namelen == SGI_ACL_FILE_SIZE && 172 strncmp(name, SGI_ACL_FILE, 173 SGI_ACL_FILE_SIZE) == 0) { 174 __xfs_xattr_put_listent( 175 context, XATTR_SYSTEM_PREFIX, 176 XATTR_SYSTEM_PREFIX_LEN, 177 XATTR_POSIX_ACL_ACCESS, 178 strlen(XATTR_POSIX_ACL_ACCESS)); 179 } else if (namelen == SGI_ACL_DEFAULT_SIZE && 180 strncmp(name, SGI_ACL_DEFAULT, 181 SGI_ACL_DEFAULT_SIZE) == 0) { 182 __xfs_xattr_put_listent( 183 context, XATTR_SYSTEM_PREFIX, 184 XATTR_SYSTEM_PREFIX_LEN, 185 XATTR_POSIX_ACL_DEFAULT, 186 strlen(XATTR_POSIX_ACL_DEFAULT)); 187 } 188 #endif 189 190 /* 191 * Only show root namespace entries if we are actually allowed to 192 * see them. 193 */ 194 if (!capable(CAP_SYS_ADMIN)) 195 return; 196 197 prefix = XATTR_TRUSTED_PREFIX; 198 prefix_len = XATTR_TRUSTED_PREFIX_LEN; 199 } else if (flags & XFS_ATTR_SECURE) { 200 prefix = XATTR_SECURITY_PREFIX; 201 prefix_len = XATTR_SECURITY_PREFIX_LEN; 202 } else { 203 prefix = XATTR_USER_PREFIX; 204 prefix_len = XATTR_USER_PREFIX_LEN; 205 } 206 207 __xfs_xattr_put_listent(context, prefix, prefix_len, name, 208 namelen); 209 return; 210 } 211 212 ssize_t 213 xfs_vn_listxattr( 214 struct dentry *dentry, 215 char *data, 216 size_t size) 217 { 218 struct xfs_attr_list_context context; 219 struct attrlist_cursor_kern cursor = { 0 }; 220 struct inode *inode = d_inode(dentry); 221 int error; 222 223 /* 224 * First read the regular on-disk attributes. 225 */ 226 memset(&context, 0, sizeof(context)); 227 context.dp = XFS_I(inode); 228 context.cursor = &cursor; 229 context.resynch = 1; 230 context.alist = size ? data : NULL; 231 context.bufsize = size; 232 context.firstu = context.bufsize; 233 context.put_listent = xfs_xattr_put_listent; 234 235 error = xfs_attr_list_int(&context); 236 if (error) 237 return error; 238 if (context.count < 0) 239 return -ERANGE; 240 241 return context.count; 242 } 243