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_trans_resv.h" 13 #include "xfs_mount.h" 14 #include "xfs_inode.h" 15 #include "xfs_da_btree.h" 16 #include "xfs_attr.h" 17 #include "xfs_acl.h" 18 #include "xfs_log.h" 19 #include "xfs_xattr.h" 20 #include "xfs_quota.h" 21 22 #include <linux/posix_acl_xattr.h> 23 24 /* 25 * Get permission to use log-assisted atomic exchange of file extents. 26 * Callers must not be running any transactions or hold any ILOCKs. 27 */ 28 static inline int 29 xfs_attr_grab_log_assist( 30 struct xfs_mount *mp) 31 { 32 int error = 0; 33 34 /* xattr update log intent items are already enabled */ 35 if (xfs_is_using_logged_xattrs(mp)) 36 return 0; 37 38 /* 39 * Check if the filesystem featureset is new enough to set this log 40 * incompat feature bit. Strictly speaking, the minimum requirement is 41 * a V5 filesystem for the superblock field, but we'll require rmap 42 * or reflink to avoid having to deal with really old kernels. 43 */ 44 if (!xfs_has_reflink(mp) && !xfs_has_rmapbt(mp)) 45 return -EOPNOTSUPP; 46 47 /* Enable log-assisted xattrs. */ 48 error = xfs_add_incompat_log_feature(mp, 49 XFS_SB_FEAT_INCOMPAT_LOG_XATTRS); 50 if (error) 51 return error; 52 xfs_set_using_logged_xattrs(mp); 53 54 xfs_warn_mount(mp, XFS_OPSTATE_WARNED_LARP, 55 "EXPERIMENTAL logged extended attributes feature in use. Use at your own risk!"); 56 57 return 0; 58 } 59 60 static inline bool 61 xfs_attr_want_log_assist( 62 struct xfs_mount *mp) 63 { 64 #ifdef DEBUG 65 /* Logged xattrs require a V5 super for log_incompat */ 66 return xfs_has_crc(mp) && xfs_globals.larp; 67 #else 68 return false; 69 #endif 70 } 71 72 /* 73 * Set or remove an xattr, having grabbed the appropriate logging resources 74 * prior to calling libxfs. Callers of this function are only required to 75 * initialize the inode, attr_filter, name, namelen, value, and valuelen fields 76 * of @args. 77 */ 78 int 79 xfs_attr_change( 80 struct xfs_da_args *args, 81 enum xfs_attr_update op) 82 { 83 struct xfs_mount *mp = args->dp->i_mount; 84 int error; 85 86 if (xfs_is_shutdown(mp)) 87 return -EIO; 88 89 error = xfs_qm_dqattach(args->dp); 90 if (error) 91 return error; 92 93 /* 94 * We have no control over the attribute names that userspace passes us 95 * to remove, so we have to allow the name lookup prior to attribute 96 * removal to fail as well. 97 */ 98 args->op_flags = XFS_DA_OP_OKNOENT; 99 100 if (xfs_attr_want_log_assist(mp)) { 101 error = xfs_attr_grab_log_assist(mp); 102 if (error) 103 return error; 104 105 args->op_flags |= XFS_DA_OP_LOGGED; 106 } 107 108 args->owner = args->dp->i_ino; 109 args->geo = mp->m_attr_geo; 110 args->whichfork = XFS_ATTR_FORK; 111 xfs_attr_sethash(args); 112 113 return xfs_attr_set(args, op, args->attr_filter & XFS_ATTR_ROOT); 114 } 115 116 117 static int 118 xfs_xattr_get(const struct xattr_handler *handler, struct dentry *unused, 119 struct inode *inode, const char *name, void *value, size_t size) 120 { 121 struct xfs_da_args args = { 122 .dp = XFS_I(inode), 123 .attr_filter = handler->flags, 124 .name = name, 125 .namelen = strlen(name), 126 .value = value, 127 .valuelen = size, 128 }; 129 int error; 130 131 if (xfs_ifork_zapped(XFS_I(inode), XFS_ATTR_FORK)) 132 return -EIO; 133 134 error = xfs_attr_get(&args); 135 if (error) 136 return error; 137 return args.valuelen; 138 } 139 140 static inline enum xfs_attr_update 141 xfs_xattr_flags_to_op( 142 int flags, 143 const void *value) 144 { 145 if (!value) 146 return XFS_ATTRUPDATE_REMOVE; 147 if (flags & XATTR_CREATE) 148 return XFS_ATTRUPDATE_CREATE; 149 if (flags & XATTR_REPLACE) 150 return XFS_ATTRUPDATE_REPLACE; 151 return XFS_ATTRUPDATE_UPSERT; 152 } 153 154 static int 155 xfs_xattr_set(const struct xattr_handler *handler, 156 struct mnt_idmap *idmap, struct dentry *unused, 157 struct inode *inode, const char *name, const void *value, 158 size_t size, int flags) 159 { 160 struct xfs_da_args args = { 161 .dp = XFS_I(inode), 162 .attr_filter = handler->flags, 163 .name = name, 164 .namelen = strlen(name), 165 .value = (void *)value, 166 .valuelen = size, 167 }; 168 int error; 169 170 error = xfs_attr_change(&args, xfs_xattr_flags_to_op(flags, value)); 171 if (!error && (handler->flags & XFS_ATTR_ROOT)) 172 xfs_forget_acl(inode, name); 173 return error; 174 } 175 176 static const struct xattr_handler xfs_xattr_user_handler = { 177 .prefix = XATTR_USER_PREFIX, 178 .flags = 0, /* no flags implies user namespace */ 179 .get = xfs_xattr_get, 180 .set = xfs_xattr_set, 181 }; 182 183 static const struct xattr_handler xfs_xattr_trusted_handler = { 184 .prefix = XATTR_TRUSTED_PREFIX, 185 .flags = XFS_ATTR_ROOT, 186 .get = xfs_xattr_get, 187 .set = xfs_xattr_set, 188 }; 189 190 static const struct xattr_handler xfs_xattr_security_handler = { 191 .prefix = XATTR_SECURITY_PREFIX, 192 .flags = XFS_ATTR_SECURE, 193 .get = xfs_xattr_get, 194 .set = xfs_xattr_set, 195 }; 196 197 const struct xattr_handler * const xfs_xattr_handlers[] = { 198 &xfs_xattr_user_handler, 199 &xfs_xattr_trusted_handler, 200 &xfs_xattr_security_handler, 201 NULL 202 }; 203 204 static void 205 __xfs_xattr_put_listent( 206 struct xfs_attr_list_context *context, 207 char *prefix, 208 int prefix_len, 209 unsigned char *name, 210 int namelen) 211 { 212 char *offset; 213 int arraytop; 214 215 if (context->count < 0 || context->seen_enough) 216 return; 217 218 if (!context->buffer) 219 goto compute_size; 220 221 arraytop = context->count + prefix_len + namelen + 1; 222 if (arraytop > context->firstu) { 223 context->count = -1; /* insufficient space */ 224 context->seen_enough = 1; 225 return; 226 } 227 offset = context->buffer + context->count; 228 memcpy(offset, prefix, prefix_len); 229 offset += prefix_len; 230 strncpy(offset, (char *)name, namelen); /* real name */ 231 offset += namelen; 232 *offset = '\0'; 233 234 compute_size: 235 context->count += prefix_len + namelen + 1; 236 return; 237 } 238 239 static void 240 xfs_xattr_put_listent( 241 struct xfs_attr_list_context *context, 242 int flags, 243 unsigned char *name, 244 int namelen, 245 void *value, 246 int valuelen) 247 { 248 char *prefix; 249 int prefix_len; 250 251 ASSERT(context->count >= 0); 252 253 /* Don't expose private xattr namespaces. */ 254 if (flags & XFS_ATTR_PRIVATE_NSP_MASK) 255 return; 256 257 if (flags & XFS_ATTR_ROOT) { 258 #ifdef CONFIG_XFS_POSIX_ACL 259 if (namelen == SGI_ACL_FILE_SIZE && 260 strncmp(name, SGI_ACL_FILE, 261 SGI_ACL_FILE_SIZE) == 0) { 262 __xfs_xattr_put_listent( 263 context, XATTR_SYSTEM_PREFIX, 264 XATTR_SYSTEM_PREFIX_LEN, 265 XATTR_POSIX_ACL_ACCESS, 266 strlen(XATTR_POSIX_ACL_ACCESS)); 267 } else if (namelen == SGI_ACL_DEFAULT_SIZE && 268 strncmp(name, SGI_ACL_DEFAULT, 269 SGI_ACL_DEFAULT_SIZE) == 0) { 270 __xfs_xattr_put_listent( 271 context, XATTR_SYSTEM_PREFIX, 272 XATTR_SYSTEM_PREFIX_LEN, 273 XATTR_POSIX_ACL_DEFAULT, 274 strlen(XATTR_POSIX_ACL_DEFAULT)); 275 } 276 #endif 277 278 /* 279 * Only show root namespace entries if we are actually allowed to 280 * see them. 281 */ 282 if (!capable(CAP_SYS_ADMIN)) 283 return; 284 285 prefix = XATTR_TRUSTED_PREFIX; 286 prefix_len = XATTR_TRUSTED_PREFIX_LEN; 287 } else if (flags & XFS_ATTR_SECURE) { 288 prefix = XATTR_SECURITY_PREFIX; 289 prefix_len = XATTR_SECURITY_PREFIX_LEN; 290 } else { 291 prefix = XATTR_USER_PREFIX; 292 prefix_len = XATTR_USER_PREFIX_LEN; 293 } 294 295 __xfs_xattr_put_listent(context, prefix, prefix_len, name, 296 namelen); 297 return; 298 } 299 300 ssize_t 301 xfs_vn_listxattr( 302 struct dentry *dentry, 303 char *data, 304 size_t size) 305 { 306 struct xfs_attr_list_context context; 307 struct inode *inode = d_inode(dentry); 308 int error; 309 310 if (xfs_ifork_zapped(XFS_I(inode), XFS_ATTR_FORK)) 311 return -EIO; 312 313 /* 314 * First read the regular on-disk attributes. 315 */ 316 memset(&context, 0, sizeof(context)); 317 context.dp = XFS_I(inode); 318 context.resynch = 1; 319 context.buffer = size ? data : NULL; 320 context.bufsize = size; 321 context.firstu = context.bufsize; 322 context.put_listent = xfs_xattr_put_listent; 323 324 error = xfs_attr_list(&context); 325 if (error) 326 return error; 327 if (context.count < 0) 328 return -ERANGE; 329 330 return context.count; 331 } 332