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 /* 114 * Some xattrs must be resistant to allocation failure at ENOSPC, e.g. 115 * creating an inode with ACLs or security attributes requires the 116 * allocation of the xattr holding that information to succeed. Hence 117 * we allow xattrs in the VFS TRUSTED, SYSTEM, POSIX_ACL and SECURITY 118 * (LSM xattr) namespaces to dip into the reserve block pool to allow 119 * manipulation of these xattrs when at ENOSPC. These VFS xattr 120 * namespaces translate to the XFS_ATTR_ROOT and XFS_ATTR_SECURE on-disk 121 * namespaces. 122 * 123 * For most of these cases, these special xattrs will fit in the inode 124 * itself and so consume no extra space or only require temporary extra 125 * space while an overwrite is being made. Hence the use of the reserved 126 * pool is largely to avoid the worst case reservation from preventing 127 * the xattr from being created at ENOSPC. 128 */ 129 return xfs_attr_set(args, op, 130 args->attr_filter & (XFS_ATTR_ROOT | XFS_ATTR_SECURE)); 131 } 132 133 134 static int 135 xfs_xattr_get(const struct xattr_handler *handler, struct dentry *unused, 136 struct inode *inode, const char *name, void *value, size_t size) 137 { 138 struct xfs_da_args args = { 139 .dp = XFS_I(inode), 140 .attr_filter = handler->flags, 141 .name = name, 142 .namelen = strlen(name), 143 .value = value, 144 .valuelen = size, 145 }; 146 int error; 147 148 if (xfs_ifork_zapped(XFS_I(inode), XFS_ATTR_FORK)) 149 return -EIO; 150 151 error = xfs_attr_get(&args); 152 if (error) 153 return error; 154 return args.valuelen; 155 } 156 157 static inline enum xfs_attr_update 158 xfs_xattr_flags_to_op( 159 int flags, 160 const void *value) 161 { 162 if (!value) 163 return XFS_ATTRUPDATE_REMOVE; 164 if (flags & XATTR_CREATE) 165 return XFS_ATTRUPDATE_CREATE; 166 if (flags & XATTR_REPLACE) 167 return XFS_ATTRUPDATE_REPLACE; 168 return XFS_ATTRUPDATE_UPSERT; 169 } 170 171 static int 172 xfs_xattr_set(const struct xattr_handler *handler, 173 struct mnt_idmap *idmap, struct dentry *unused, 174 struct inode *inode, const char *name, const void *value, 175 size_t size, int flags) 176 { 177 struct xfs_da_args args = { 178 .dp = XFS_I(inode), 179 .attr_filter = handler->flags, 180 .name = name, 181 .namelen = strlen(name), 182 .value = (void *)value, 183 .valuelen = size, 184 }; 185 int error; 186 187 error = xfs_attr_change(&args, xfs_xattr_flags_to_op(flags, value)); 188 if (!error && (handler->flags & XFS_ATTR_ROOT)) 189 xfs_forget_acl(inode, name); 190 return error; 191 } 192 193 static const struct xattr_handler xfs_xattr_user_handler = { 194 .prefix = XATTR_USER_PREFIX, 195 .flags = 0, /* no flags implies user namespace */ 196 .get = xfs_xattr_get, 197 .set = xfs_xattr_set, 198 }; 199 200 static const struct xattr_handler xfs_xattr_trusted_handler = { 201 .prefix = XATTR_TRUSTED_PREFIX, 202 .flags = XFS_ATTR_ROOT, 203 .get = xfs_xattr_get, 204 .set = xfs_xattr_set, 205 }; 206 207 static const struct xattr_handler xfs_xattr_security_handler = { 208 .prefix = XATTR_SECURITY_PREFIX, 209 .flags = XFS_ATTR_SECURE, 210 .get = xfs_xattr_get, 211 .set = xfs_xattr_set, 212 }; 213 214 const struct xattr_handler * const xfs_xattr_handlers[] = { 215 &xfs_xattr_user_handler, 216 &xfs_xattr_trusted_handler, 217 &xfs_xattr_security_handler, 218 NULL 219 }; 220 221 static void 222 __xfs_xattr_put_listent( 223 struct xfs_attr_list_context *context, 224 char *prefix, 225 int prefix_len, 226 unsigned char *name, 227 int namelen) 228 { 229 char *offset; 230 int arraytop; 231 232 if (context->count < 0 || context->seen_enough) 233 return; 234 235 if (!context->buffer) 236 goto compute_size; 237 238 arraytop = context->count + prefix_len + namelen + 1; 239 if (arraytop > context->firstu) { 240 context->count = -1; /* insufficient space */ 241 context->seen_enough = 1; 242 return; 243 } 244 offset = context->buffer + context->count; 245 memcpy(offset, prefix, prefix_len); 246 offset += prefix_len; 247 strncpy(offset, (char *)name, namelen); /* real name */ 248 offset += namelen; 249 *offset = '\0'; 250 251 compute_size: 252 context->count += prefix_len + namelen + 1; 253 return; 254 } 255 256 static void 257 xfs_xattr_put_listent( 258 struct xfs_attr_list_context *context, 259 int flags, 260 unsigned char *name, 261 int namelen, 262 void *value, 263 int valuelen) 264 { 265 char *prefix; 266 int prefix_len; 267 268 ASSERT(context->count >= 0); 269 270 /* Don't expose private xattr namespaces. */ 271 if (flags & XFS_ATTR_PRIVATE_NSP_MASK) 272 return; 273 274 if (flags & XFS_ATTR_ROOT) { 275 #ifdef CONFIG_XFS_POSIX_ACL 276 if (namelen == SGI_ACL_FILE_SIZE && 277 strncmp(name, SGI_ACL_FILE, 278 SGI_ACL_FILE_SIZE) == 0) { 279 __xfs_xattr_put_listent( 280 context, XATTR_SYSTEM_PREFIX, 281 XATTR_SYSTEM_PREFIX_LEN, 282 XATTR_POSIX_ACL_ACCESS, 283 strlen(XATTR_POSIX_ACL_ACCESS)); 284 } else if (namelen == SGI_ACL_DEFAULT_SIZE && 285 strncmp(name, SGI_ACL_DEFAULT, 286 SGI_ACL_DEFAULT_SIZE) == 0) { 287 __xfs_xattr_put_listent( 288 context, XATTR_SYSTEM_PREFIX, 289 XATTR_SYSTEM_PREFIX_LEN, 290 XATTR_POSIX_ACL_DEFAULT, 291 strlen(XATTR_POSIX_ACL_DEFAULT)); 292 } 293 #endif 294 295 /* 296 * Only show root namespace entries if we are actually allowed to 297 * see them. 298 */ 299 if (!capable(CAP_SYS_ADMIN)) 300 return; 301 302 prefix = XATTR_TRUSTED_PREFIX; 303 prefix_len = XATTR_TRUSTED_PREFIX_LEN; 304 } else if (flags & XFS_ATTR_SECURE) { 305 prefix = XATTR_SECURITY_PREFIX; 306 prefix_len = XATTR_SECURITY_PREFIX_LEN; 307 } else { 308 prefix = XATTR_USER_PREFIX; 309 prefix_len = XATTR_USER_PREFIX_LEN; 310 } 311 312 __xfs_xattr_put_listent(context, prefix, prefix_len, name, 313 namelen); 314 return; 315 } 316 317 ssize_t 318 xfs_vn_listxattr( 319 struct dentry *dentry, 320 char *data, 321 size_t size) 322 { 323 struct xfs_attr_list_context context; 324 struct inode *inode = d_inode(dentry); 325 int error; 326 327 if (xfs_ifork_zapped(XFS_I(inode), XFS_ATTR_FORK)) 328 return -EIO; 329 330 /* 331 * First read the regular on-disk attributes. 332 */ 333 memset(&context, 0, sizeof(context)); 334 context.dp = XFS_I(inode); 335 context.resynch = 1; 336 context.buffer = size ? data : NULL; 337 context.bufsize = size; 338 context.firstu = context.bufsize; 339 context.put_listent = xfs_xattr_put_listent; 340 341 error = xfs_attr_list(&context); 342 if (error) 343 return error; 344 if (context.count < 0) 345 return -ERANGE; 346 347 return context.count; 348 } 349
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.