LCOV - code coverage report
Current view: top level - fs/xfs - xfs_xattr.c (source / functions) Hit Total Coverage
Test: fstests of 6.5.0-rc3-djwa @ Mon Jul 31 20:08:17 PDT 2023 Lines: 90 95 94.7 %
Date: 2023-07-31 20:08:17 Functions: 8 8 100.0 %

          Line data    Source code
       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             : 
      21             : #include <linux/posix_acl_xattr.h>
      22             : 
      23             : /*
      24             :  * Get permission to use log-assisted atomic exchange of file extents.
      25             :  *
      26             :  * Callers must not be running any transactions or hold any inode locks, and
      27             :  * they must release the permission by calling xlog_drop_incompat_feat
      28             :  * when they're done.
      29             :  */
      30             : static inline int
      31          98 : xfs_attr_grab_log_assist(
      32             :         struct xfs_mount        *mp)
      33             : {
      34          98 :         int                     error = 0;
      35             : 
      36             :         /*
      37             :          * Protect ourselves from an idle log clearing the logged xattrs log
      38             :          * incompat feature bit.
      39             :          */
      40          98 :         xlog_use_incompat_feat(mp->m_log);
      41             : 
      42             :         /*
      43             :          * If log-assisted xattrs are already enabled, the caller can use the
      44             :          * log assisted swap functions with the log-incompat reference we got.
      45             :          */
      46         196 :         if (xfs_sb_version_haslogxattrs(&mp->m_sb))
      47             :                 return 0;
      48             : 
      49             :         /* Enable log-assisted xattrs. */
      50          58 :         error = xfs_add_incompat_log_feature(mp,
      51             :                         XFS_SB_FEAT_INCOMPAT_LOG_XATTRS);
      52          58 :         if (error)
      53           0 :                 goto drop_incompat;
      54             : 
      55          58 :         xfs_warn_mount(mp, XFS_OPSTATE_WARNED_LARP,
      56             :  "EXPERIMENTAL logged extended attributes feature in use. Use at your own risk!");
      57             : 
      58             :         return 0;
      59             : drop_incompat:
      60           0 :         xlog_drop_incompat_feat(mp->m_log);
      61           0 :         return error;
      62             : }
      63             : 
      64             : static inline void
      65             : xfs_attr_rele_log_assist(
      66             :         struct xfs_mount        *mp)
      67             : {
      68          98 :         xlog_drop_incompat_feat(mp->m_log);
      69          98 : }
      70             : 
      71             : static inline bool
      72   102234084 : xfs_attr_want_log_assist(
      73             :         struct xfs_mount        *mp)
      74             : {
      75             : #ifdef DEBUG
      76             :         /* Logged xattrs require a V5 super for log_incompat */
      77   102234084 :         return xfs_has_crc(mp) && xfs_globals.larp;
      78             : #else
      79             :         return false;
      80             : #endif
      81             : }
      82             : 
      83             : /*
      84             :  * Set or remove an xattr, having grabbed the appropriate logging resources
      85             :  * prior to calling libxfs.
      86             :  */
      87             : int
      88   102227087 : xfs_attr_change(
      89             :         struct xfs_da_args      *args)
      90             : {
      91   102227087 :         struct xfs_mount        *mp = args->dp->i_mount;
      92   102227087 :         bool                    use_logging = false;
      93   102227087 :         int                     error;
      94             : 
      95   102227087 :         ASSERT(!(args->op_flags & XFS_DA_OP_LOGGED));
      96             : 
      97   102227087 :         if (xfs_attr_want_log_assist(mp)) {
      98          98 :                 error = xfs_attr_grab_log_assist(mp);
      99          98 :                 if (error)
     100             :                         return error;
     101             : 
     102          98 :                 args->op_flags |= XFS_DA_OP_LOGGED;
     103          98 :                 use_logging = true;
     104             :         }
     105             : 
     106   102244298 :         error = xfs_attr_set(args);
     107             : 
     108   102239687 :         if (use_logging)
     109          98 :                 xfs_attr_rele_log_assist(mp);
     110             :         return error;
     111             : }
     112             : 
     113             : 
     114             : static int
     115    18347429 : xfs_xattr_get(const struct xattr_handler *handler, struct dentry *unused,
     116             :                 struct inode *inode, const char *name, void *value, size_t size)
     117             : {
     118    18347429 :         struct xfs_da_args      args = {
     119             :                 .dp             = XFS_I(inode),
     120    18347429 :                 .attr_filter    = handler->flags,
     121             :                 .name           = name,
     122             :                 .namelen        = strlen(name),
     123             :                 .value          = value,
     124             :                 .valuelen       = size,
     125             :         };
     126    18347429 :         int                     error;
     127             : 
     128    18347429 :         error = xfs_attr_get(&args);
     129    18348058 :         if (error)
     130             :                 return error;
     131     7557902 :         return args.valuelen;
     132             : }
     133             : 
     134             : static int
     135   100324732 : xfs_xattr_set(const struct xattr_handler *handler,
     136             :               struct mnt_idmap *idmap, struct dentry *unused,
     137             :               struct inode *inode, const char *name, const void *value,
     138             :               size_t size, int flags)
     139             : {
     140   100324732 :         struct xfs_da_args      args = {
     141             :                 .dp             = XFS_I(inode),
     142   100324732 :                 .attr_filter    = handler->flags,
     143             :                 .attr_flags     = flags,
     144             :                 .name           = name,
     145             :                 .namelen        = strlen(name),
     146             :                 .value          = (void *)value,
     147             :                 .valuelen       = size,
     148             :         };
     149   100324732 :         int                     error;
     150             : 
     151   100324732 :         error = xfs_attr_change(&args);
     152   100350943 :         if (!error && (handler->flags & XFS_ATTR_ROOT))
     153       83152 :                 xfs_forget_acl(inode, name);
     154   100350943 :         return error;
     155             : }
     156             : 
     157             : static const struct xattr_handler xfs_xattr_user_handler = {
     158             :         .prefix = XATTR_USER_PREFIX,
     159             :         .flags  = 0, /* no flags implies user namespace */
     160             :         .get    = xfs_xattr_get,
     161             :         .set    = xfs_xattr_set,
     162             : };
     163             : 
     164             : static const struct xattr_handler xfs_xattr_trusted_handler = {
     165             :         .prefix = XATTR_TRUSTED_PREFIX,
     166             :         .flags  = XFS_ATTR_ROOT,
     167             :         .get    = xfs_xattr_get,
     168             :         .set    = xfs_xattr_set,
     169             : };
     170             : 
     171             : static const struct xattr_handler xfs_xattr_security_handler = {
     172             :         .prefix = XATTR_SECURITY_PREFIX,
     173             :         .flags  = XFS_ATTR_SECURE,
     174             :         .get    = xfs_xattr_get,
     175             :         .set    = xfs_xattr_set,
     176             : };
     177             : 
     178             : const struct xattr_handler *xfs_xattr_handlers[] = {
     179             :         &xfs_xattr_user_handler,
     180             :         &xfs_xattr_trusted_handler,
     181             :         &xfs_xattr_security_handler,
     182             :         NULL
     183             : };
     184             : 
     185             : static void
     186   475698264 : __xfs_xattr_put_listent(
     187             :         struct xfs_attr_list_context *context,
     188             :         char *prefix,
     189             :         int prefix_len,
     190             :         unsigned char *name,
     191             :         int namelen)
     192             : {
     193   475698264 :         char *offset;
     194   475698264 :         int arraytop;
     195             : 
     196   475698264 :         if (context->count < 0 || context->seen_enough)
     197             :                 return;
     198             : 
     199   475698262 :         if (!context->buffer)
     200   119184508 :                 goto compute_size;
     201             : 
     202   356513754 :         arraytop = context->count + prefix_len + namelen + 1;
     203   356513754 :         if (arraytop > context->firstu) {
     204           8 :                 context->count = -1; /* insufficient space */
     205           8 :                 context->seen_enough = 1;
     206           8 :                 return;
     207             :         }
     208   356513746 :         offset = context->buffer + context->count;
     209   713027492 :         memcpy(offset, prefix, prefix_len);
     210   356513746 :         offset += prefix_len;
     211   356513746 :         strncpy(offset, (char *)name, namelen);                 /* real name */
     212   356513746 :         offset += namelen;
     213   356513746 :         *offset = '\0';
     214             : 
     215   475698254 : compute_size:
     216   475698254 :         context->count += prefix_len + namelen + 1;
     217   475698254 :         return;
     218             : }
     219             : 
     220             : static void
     221   475256923 : xfs_xattr_put_listent(
     222             :         struct xfs_attr_list_context *context,
     223             :         int             flags,
     224             :         unsigned char   *name,
     225             :         int             namelen,
     226             :         int             valuelen)
     227             : {
     228   475256923 :         char *prefix;
     229   475256923 :         int prefix_len;
     230             : 
     231   475256923 :         ASSERT(context->count >= 0);
     232             : 
     233   475256923 :         if (flags & XFS_ATTR_ROOT) {
     234             : #ifdef CONFIG_XFS_POSIX_ACL
     235         830 :                 if (namelen == SGI_ACL_FILE_SIZE &&
     236           2 :                     strncmp(name, SGI_ACL_FILE,
     237             :                             SGI_ACL_FILE_SIZE) == 0) {
     238           2 :                         __xfs_xattr_put_listent(
     239             :                                         context, XATTR_SYSTEM_PREFIX,
     240             :                                         XATTR_SYSTEM_PREFIX_LEN,
     241             :                                         XATTR_POSIX_ACL_ACCESS,
     242             :                                         strlen(XATTR_POSIX_ACL_ACCESS));
     243         828 :                 } else if (namelen == SGI_ACL_DEFAULT_SIZE &&
     244           0 :                          strncmp(name, SGI_ACL_DEFAULT,
     245             :                                  SGI_ACL_DEFAULT_SIZE) == 0) {
     246           0 :                         __xfs_xattr_put_listent(
     247             :                                         context, XATTR_SYSTEM_PREFIX,
     248             :                                         XATTR_SYSTEM_PREFIX_LEN,
     249             :                                         XATTR_POSIX_ACL_DEFAULT,
     250             :                                         strlen(XATTR_POSIX_ACL_DEFAULT));
     251             :                 }
     252             : #endif
     253             : 
     254             :                 /*
     255             :                  * Only show root namespace entries if we are actually allowed to
     256             :                  * see them.
     257             :                  */
     258         830 :                 if (!capable(CAP_SYS_ADMIN))
     259             :                         return;
     260             : 
     261             :                 prefix = XATTR_TRUSTED_PREFIX;
     262             :                 prefix_len = XATTR_TRUSTED_PREFIX_LEN;
     263   475256093 :         } else if (flags & XFS_ATTR_SECURE) {
     264             :                 prefix = XATTR_SECURITY_PREFIX;
     265             :                 prefix_len = XATTR_SECURITY_PREFIX_LEN;
     266             :         } else {
     267   475272196 :                 prefix = XATTR_USER_PREFIX;
     268   475272196 :                 prefix_len = XATTR_USER_PREFIX_LEN;
     269             :         }
     270             : 
     271   475256923 :         __xfs_xattr_put_listent(context, prefix, prefix_len, name,
     272             :                                 namelen);
     273   475256923 :         return;
     274             : }
     275             : 
     276             : ssize_t
     277    34509579 : xfs_vn_listxattr(
     278             :         struct dentry   *dentry,
     279             :         char            *data,
     280             :         size_t          size)
     281             : {
     282    34509579 :         struct xfs_attr_list_context context;
     283    34509579 :         struct inode    *inode = d_inode(dentry);
     284    34509579 :         int             error;
     285             : 
     286             :         /*
     287             :          * First read the regular on-disk attributes.
     288             :          */
     289    34509579 :         memset(&context, 0, sizeof(context));
     290    34509579 :         context.dp = XFS_I(inode);
     291    34509579 :         context.resynch = 1;
     292    34509579 :         context.buffer = size ? data : NULL;
     293    34509579 :         context.bufsize = size;
     294    34509579 :         context.firstu = context.bufsize;
     295    34509579 :         context.put_listent = xfs_xattr_put_listent;
     296             : 
     297    34509579 :         error = xfs_attr_list(&context);
     298    34509475 :         if (error)
     299           2 :                 return error;
     300    34509473 :         if (context.count < 0)
     301           8 :                 return -ERANGE;
     302             : 
     303             :         return context.count;
     304             : }

Generated by: LCOV version 1.14