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_shared.h" 9 #include "xfs_format.h" 10 #include "xfs_log_format.h" 11 #include "xfs_da_format.h" 12 #include "xfs_inode.h" 13 #include "xfs_attr.h" 14 #include "xfs_acl.h" 15 16 #include <linux/posix_acl_xattr.h> 17 #include <linux/xattr.h> 18 19 20 static int 21 xfs_xattr_get(const struct xattr_handler *handler, struct dentry *unused, 22 struct inode *inode, const char *name, void *value, size_t size) 23 { 24 int xflags = handler->flags; 25 struct xfs_inode *ip = XFS_I(inode); 26 int error, asize = size; 27 size_t namelen = strlen(name); 28 29 /* Convert Linux syscall to XFS internal ATTR flags */ 30 if (!size) { 31 xflags |= ATTR_KERNOVAL; 32 value = NULL; 33 } 34 35 error = xfs_attr_get(ip, name, namelen, (unsigned char **)&value, 36 &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 size_t namelen = strlen(name); 73 74 /* Convert Linux syscall to XFS internal ATTR flags */ 75 if (flags & XATTR_CREATE) 76 xflags |= ATTR_CREATE; 77 if (flags & XATTR_REPLACE) 78 xflags |= ATTR_REPLACE; 79 80 if (value) 81 error = xfs_attr_set(ip, name, namelen, (void *)value, size, 82 xflags); 83 else 84 error = xfs_attr_remove(ip, name, namelen, xflags); 85 if (!error) 86 xfs_forget_acl(inode, name, xflags); 87 88 return error; 89 } 90 91 static const struct xattr_handler xfs_xattr_user_handler = { 92 .prefix = XATTR_USER_PREFIX, 93 .flags = 0, /* no flags implies user namespace */ 94 .get = xfs_xattr_get, 95 .set = xfs_xattr_set, 96 }; 97 98 static const struct xattr_handler xfs_xattr_trusted_handler = { 99 .prefix = XATTR_TRUSTED_PREFIX, 100 .flags = ATTR_ROOT, 101 .get = xfs_xattr_get, 102 .set = xfs_xattr_set, 103 }; 104 105 static const struct xattr_handler xfs_xattr_security_handler = { 106 .prefix = XATTR_SECURITY_PREFIX, 107 .flags = ATTR_SECURE, 108 .get = xfs_xattr_get, 109 .set = xfs_xattr_set, 110 }; 111 112 const struct xattr_handler *xfs_xattr_handlers[] = { 113 &xfs_xattr_user_handler, 114 &xfs_xattr_trusted_handler, 115 &xfs_xattr_security_handler, 116 #ifdef CONFIG_XFS_POSIX_ACL 117 &posix_acl_access_xattr_handler, 118 &posix_acl_default_xattr_handler, 119 #endif 120 NULL 121 }; 122 123 static void 124 __xfs_xattr_put_listent( 125 struct xfs_attr_list_context *context, 126 char *prefix, 127 int prefix_len, 128 unsigned char *name, 129 int namelen) 130 { 131 char *offset; 132 int arraytop; 133 134 if (context->count < 0 || context->seen_enough) 135 return; 136 137 if (!context->alist) 138 goto compute_size; 139 140 arraytop = context->count + prefix_len + namelen + 1; 141 if (arraytop > context->firstu) { 142 context->count = -1; /* insufficient space */ 143 context->seen_enough = 1; 144 return; 145 } 146 offset = (char *)context->alist + context->count; 147 strncpy(offset, prefix, prefix_len); 148 offset += prefix_len; 149 strncpy(offset, (char *)name, namelen); /* real name */ 150 offset += namelen; 151 *offset = '\0'; 152 153 compute_size: 154 context->count += prefix_len + namelen + 1; 155 return; 156 } 157 158 static void 159 xfs_xattr_put_listent( 160 struct xfs_attr_list_context *context, 161 int flags, 162 unsigned char *name, 163 int namelen, 164 int valuelen) 165 { 166 char *prefix; 167 int prefix_len; 168 169 ASSERT(context->count >= 0); 170 171 if (flags & XFS_ATTR_ROOT) { 172 #ifdef CONFIG_XFS_POSIX_ACL 173 if (namelen == SGI_ACL_FILE_SIZE && 174 strncmp(name, SGI_ACL_FILE, 175 SGI_ACL_FILE_SIZE) == 0) { 176 __xfs_xattr_put_listent( 177 context, XATTR_SYSTEM_PREFIX, 178 XATTR_SYSTEM_PREFIX_LEN, 179 XATTR_POSIX_ACL_ACCESS, 180 strlen(XATTR_POSIX_ACL_ACCESS)); 181 } else if (namelen == SGI_ACL_DEFAULT_SIZE && 182 strncmp(name, SGI_ACL_DEFAULT, 183 SGI_ACL_DEFAULT_SIZE) == 0) { 184 __xfs_xattr_put_listent( 185 context, XATTR_SYSTEM_PREFIX, 186 XATTR_SYSTEM_PREFIX_LEN, 187 XATTR_POSIX_ACL_DEFAULT, 188 strlen(XATTR_POSIX_ACL_DEFAULT)); 189 } 190 #endif 191 192 /* 193 * Only show root namespace entries if we are actually allowed to 194 * see them. 195 */ 196 if (!capable(CAP_SYS_ADMIN)) 197 return; 198 199 prefix = XATTR_TRUSTED_PREFIX; 200 prefix_len = XATTR_TRUSTED_PREFIX_LEN; 201 } else if (flags & XFS_ATTR_SECURE) { 202 prefix = XATTR_SECURITY_PREFIX; 203 prefix_len = XATTR_SECURITY_PREFIX_LEN; 204 } else { 205 prefix = XATTR_USER_PREFIX; 206 prefix_len = XATTR_USER_PREFIX_LEN; 207 } 208 209 __xfs_xattr_put_listent(context, prefix, prefix_len, name, 210 namelen); 211 return; 212 } 213 214 ssize_t 215 xfs_vn_listxattr( 216 struct dentry *dentry, 217 char *data, 218 size_t size) 219 { 220 struct xfs_attr_list_context context; 221 struct attrlist_cursor_kern cursor = { 0 }; 222 struct inode *inode = d_inode(dentry); 223 int error; 224 225 /* 226 * First read the regular on-disk attributes. 227 */ 228 memset(&context, 0, sizeof(context)); 229 context.dp = XFS_I(inode); 230 context.cursor = &cursor; 231 context.resynch = 1; 232 context.alist = size ? data : NULL; 233 context.bufsize = size; 234 context.firstu = context.bufsize; 235 context.put_listent = xfs_xattr_put_listent; 236 237 error = xfs_attr_list_int(&context); 238 if (error) 239 return error; 240 if (context.count < 0) 241 return -ERANGE; 242 243 return context.count; 244 } 245