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