349 lines · c
1// SPDX-License-Identifier: GPL-2.02/*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 */28static inline int29xfs_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 log40 * incompat feature bit. Strictly speaking, the minimum requirement is41 * a V5 filesystem for the superblock field, but we'll require rmap42 * 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 60static inline bool61xfs_attr_want_log_assist(62 struct xfs_mount *mp)63{64#ifdef DEBUG65 /* Logged xattrs require a V5 super for log_incompat */66 return xfs_has_crc(mp) && xfs_globals.larp;67#else68 return false;69#endif70}71 72/*73 * Set or remove an xattr, having grabbed the appropriate logging resources74 * prior to calling libxfs. Callers of this function are only required to75 * initialize the inode, attr_filter, name, namelen, value, and valuelen fields76 * of @args.77 */78int79xfs_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 us95 * to remove, so we have to allow the name lookup prior to attribute96 * 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 the116 * allocation of the xattr holding that information to succeed. Hence117 * we allow xattrs in the VFS TRUSTED, SYSTEM, POSIX_ACL and SECURITY118 * (LSM xattr) namespaces to dip into the reserve block pool to allow119 * manipulation of these xattrs when at ENOSPC. These VFS xattr120 * namespaces translate to the XFS_ATTR_ROOT and XFS_ATTR_SECURE on-disk121 * namespaces.122 *123 * For most of these cases, these special xattrs will fit in the inode124 * itself and so consume no extra space or only require temporary extra125 * space while an overwrite is being made. Hence the use of the reserved126 * pool is largely to avoid the worst case reservation from preventing127 * 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 134static int135xfs_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 157static inline enum xfs_attr_update158xfs_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 171static int172xfs_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 193static 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 200static 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 207static 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 214const struct xattr_handler * const xfs_xattr_handlers[] = {215 &xfs_xattr_user_handler,216 &xfs_xattr_trusted_handler,217 &xfs_xattr_security_handler,218 NULL219};220 221static void222__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 251compute_size:252 context->count += prefix_len + namelen + 1;253 return;254}255 256static void257xfs_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_ACL276 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#endif294 295 /*296 * Only show root namespace entries if we are actually allowed to297 * 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 317ssize_t318xfs_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