Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Copyright (C) 2008 Christoph Hellwig.
0004  * Portions Copyright (C) 2000-2008 Silicon Graphics, Inc.
0005  */
0006 
0007 #include "xfs.h"
0008 #include "xfs_shared.h"
0009 #include "xfs_format.h"
0010 #include "xfs_log_format.h"
0011 #include "xfs_da_format.h"
0012 #include "xfs_trans_resv.h"
0013 #include "xfs_mount.h"
0014 #include "xfs_inode.h"
0015 #include "xfs_da_btree.h"
0016 #include "xfs_attr.h"
0017 #include "xfs_acl.h"
0018 #include "xfs_log.h"
0019 #include "xfs_xattr.h"
0020 
0021 #include <linux/posix_acl_xattr.h>
0022 
0023 /*
0024  * Get permission to use log-assisted atomic exchange of file extents.
0025  *
0026  * Callers must not be running any transactions or hold any inode locks, and
0027  * they must release the permission by calling xlog_drop_incompat_feat
0028  * when they're done.
0029  */
0030 static inline int
0031 xfs_attr_grab_log_assist(
0032     struct xfs_mount    *mp)
0033 {
0034     int         error = 0;
0035 
0036     /*
0037      * Protect ourselves from an idle log clearing the logged xattrs log
0038      * incompat feature bit.
0039      */
0040     xlog_use_incompat_feat(mp->m_log);
0041 
0042     /*
0043      * If log-assisted xattrs are already enabled, the caller can use the
0044      * log assisted swap functions with the log-incompat reference we got.
0045      */
0046     if (xfs_sb_version_haslogxattrs(&mp->m_sb))
0047         return 0;
0048 
0049     /* Enable log-assisted xattrs. */
0050     error = xfs_add_incompat_log_feature(mp,
0051             XFS_SB_FEAT_INCOMPAT_LOG_XATTRS);
0052     if (error)
0053         goto drop_incompat;
0054 
0055     xfs_warn_mount(mp, XFS_OPSTATE_WARNED_LARP,
0056  "EXPERIMENTAL logged extended attributes feature in use. Use at your own risk!");
0057 
0058     return 0;
0059 drop_incompat:
0060     xlog_drop_incompat_feat(mp->m_log);
0061     return error;
0062 }
0063 
0064 static inline void
0065 xfs_attr_rele_log_assist(
0066     struct xfs_mount    *mp)
0067 {
0068     xlog_drop_incompat_feat(mp->m_log);
0069 }
0070 
0071 static inline bool
0072 xfs_attr_want_log_assist(
0073     struct xfs_mount    *mp)
0074 {
0075 #ifdef DEBUG
0076     /* Logged xattrs require a V5 super for log_incompat */
0077     return xfs_has_crc(mp) && xfs_globals.larp;
0078 #else
0079     return false;
0080 #endif
0081 }
0082 
0083 /*
0084  * Set or remove an xattr, having grabbed the appropriate logging resources
0085  * prior to calling libxfs.
0086  */
0087 int
0088 xfs_attr_change(
0089     struct xfs_da_args  *args)
0090 {
0091     struct xfs_mount    *mp = args->dp->i_mount;
0092     bool            use_logging = false;
0093     int         error;
0094 
0095     ASSERT(!(args->op_flags & XFS_DA_OP_LOGGED));
0096 
0097     if (xfs_attr_want_log_assist(mp)) {
0098         error = xfs_attr_grab_log_assist(mp);
0099         if (error)
0100             return error;
0101 
0102         args->op_flags |= XFS_DA_OP_LOGGED;
0103         use_logging = true;
0104     }
0105 
0106     error = xfs_attr_set(args);
0107 
0108     if (use_logging)
0109         xfs_attr_rele_log_assist(mp);
0110     return error;
0111 }
0112 
0113 
0114 static int
0115 xfs_xattr_get(const struct xattr_handler *handler, struct dentry *unused,
0116         struct inode *inode, const char *name, void *value, size_t size)
0117 {
0118     struct xfs_da_args  args = {
0119         .dp     = XFS_I(inode),
0120         .attr_filter    = handler->flags,
0121         .name       = name,
0122         .namelen    = strlen(name),
0123         .value      = value,
0124         .valuelen   = size,
0125     };
0126     int         error;
0127 
0128     error = xfs_attr_get(&args);
0129     if (error)
0130         return error;
0131     return args.valuelen;
0132 }
0133 
0134 static int
0135 xfs_xattr_set(const struct xattr_handler *handler,
0136           struct user_namespace *mnt_userns, struct dentry *unused,
0137           struct inode *inode, const char *name, const void *value,
0138           size_t size, int flags)
0139 {
0140     struct xfs_da_args  args = {
0141         .dp     = XFS_I(inode),
0142         .attr_filter    = handler->flags,
0143         .attr_flags = flags,
0144         .name       = name,
0145         .namelen    = strlen(name),
0146         .value      = (void *)value,
0147         .valuelen   = size,
0148     };
0149     int         error;
0150 
0151     error = xfs_attr_change(&args);
0152     if (!error && (handler->flags & XFS_ATTR_ROOT))
0153         xfs_forget_acl(inode, name);
0154     return error;
0155 }
0156 
0157 static const struct xattr_handler xfs_xattr_user_handler = {
0158     .prefix = XATTR_USER_PREFIX,
0159     .flags  = 0, /* no flags implies user namespace */
0160     .get    = xfs_xattr_get,
0161     .set    = xfs_xattr_set,
0162 };
0163 
0164 static const struct xattr_handler xfs_xattr_trusted_handler = {
0165     .prefix = XATTR_TRUSTED_PREFIX,
0166     .flags  = XFS_ATTR_ROOT,
0167     .get    = xfs_xattr_get,
0168     .set    = xfs_xattr_set,
0169 };
0170 
0171 static const struct xattr_handler xfs_xattr_security_handler = {
0172     .prefix = XATTR_SECURITY_PREFIX,
0173     .flags  = XFS_ATTR_SECURE,
0174     .get    = xfs_xattr_get,
0175     .set    = xfs_xattr_set,
0176 };
0177 
0178 const struct xattr_handler *xfs_xattr_handlers[] = {
0179     &xfs_xattr_user_handler,
0180     &xfs_xattr_trusted_handler,
0181     &xfs_xattr_security_handler,
0182 #ifdef CONFIG_XFS_POSIX_ACL
0183     &posix_acl_access_xattr_handler,
0184     &posix_acl_default_xattr_handler,
0185 #endif
0186     NULL
0187 };
0188 
0189 static void
0190 __xfs_xattr_put_listent(
0191     struct xfs_attr_list_context *context,
0192     char *prefix,
0193     int prefix_len,
0194     unsigned char *name,
0195     int namelen)
0196 {
0197     char *offset;
0198     int arraytop;
0199 
0200     if (context->count < 0 || context->seen_enough)
0201         return;
0202 
0203     if (!context->buffer)
0204         goto compute_size;
0205 
0206     arraytop = context->count + prefix_len + namelen + 1;
0207     if (arraytop > context->firstu) {
0208         context->count = -1;    /* insufficient space */
0209         context->seen_enough = 1;
0210         return;
0211     }
0212     offset = context->buffer + context->count;
0213     strncpy(offset, prefix, prefix_len);
0214     offset += prefix_len;
0215     strncpy(offset, (char *)name, namelen);         /* real name */
0216     offset += namelen;
0217     *offset = '\0';
0218 
0219 compute_size:
0220     context->count += prefix_len + namelen + 1;
0221     return;
0222 }
0223 
0224 static void
0225 xfs_xattr_put_listent(
0226     struct xfs_attr_list_context *context,
0227     int     flags,
0228     unsigned char   *name,
0229     int     namelen,
0230     int     valuelen)
0231 {
0232     char *prefix;
0233     int prefix_len;
0234 
0235     ASSERT(context->count >= 0);
0236 
0237     if (flags & XFS_ATTR_ROOT) {
0238 #ifdef CONFIG_XFS_POSIX_ACL
0239         if (namelen == SGI_ACL_FILE_SIZE &&
0240             strncmp(name, SGI_ACL_FILE,
0241                 SGI_ACL_FILE_SIZE) == 0) {
0242             __xfs_xattr_put_listent(
0243                     context, XATTR_SYSTEM_PREFIX,
0244                     XATTR_SYSTEM_PREFIX_LEN,
0245                     XATTR_POSIX_ACL_ACCESS,
0246                     strlen(XATTR_POSIX_ACL_ACCESS));
0247         } else if (namelen == SGI_ACL_DEFAULT_SIZE &&
0248              strncmp(name, SGI_ACL_DEFAULT,
0249                  SGI_ACL_DEFAULT_SIZE) == 0) {
0250             __xfs_xattr_put_listent(
0251                     context, XATTR_SYSTEM_PREFIX,
0252                     XATTR_SYSTEM_PREFIX_LEN,
0253                     XATTR_POSIX_ACL_DEFAULT,
0254                     strlen(XATTR_POSIX_ACL_DEFAULT));
0255         }
0256 #endif
0257 
0258         /*
0259          * Only show root namespace entries if we are actually allowed to
0260          * see them.
0261          */
0262         if (!capable(CAP_SYS_ADMIN))
0263             return;
0264 
0265         prefix = XATTR_TRUSTED_PREFIX;
0266         prefix_len = XATTR_TRUSTED_PREFIX_LEN;
0267     } else if (flags & XFS_ATTR_SECURE) {
0268         prefix = XATTR_SECURITY_PREFIX;
0269         prefix_len = XATTR_SECURITY_PREFIX_LEN;
0270     } else {
0271         prefix = XATTR_USER_PREFIX;
0272         prefix_len = XATTR_USER_PREFIX_LEN;
0273     }
0274 
0275     __xfs_xattr_put_listent(context, prefix, prefix_len, name,
0276                 namelen);
0277     return;
0278 }
0279 
0280 ssize_t
0281 xfs_vn_listxattr(
0282     struct dentry   *dentry,
0283     char        *data,
0284     size_t      size)
0285 {
0286     struct xfs_attr_list_context context;
0287     struct inode    *inode = d_inode(dentry);
0288     int     error;
0289 
0290     /*
0291      * First read the regular on-disk attributes.
0292      */
0293     memset(&context, 0, sizeof(context));
0294     context.dp = XFS_I(inode);
0295     context.resynch = 1;
0296     context.buffer = size ? data : NULL;
0297     context.bufsize = size;
0298     context.firstu = context.bufsize;
0299     context.put_listent = xfs_xattr_put_listent;
0300 
0301     error = xfs_attr_list(&context);
0302     if (error)
0303         return error;
0304     if (context.count < 0)
0305         return -ERANGE;
0306 
0307     return context.count;
0308 }