linux/fs/xfs/xfs_xattr.c
<<
>>
Prefs
   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_attr.h"
  16#include "xfs_acl.h"
  17#include "xfs_da_btree.h"
  18
  19#include <linux/posix_acl_xattr.h>
  20
  21
  22static int
  23xfs_xattr_get(const struct xattr_handler *handler, struct dentry *unused,
  24                struct inode *inode, const char *name, void *value, size_t size)
  25{
  26        struct xfs_da_args      args = {
  27                .dp             = XFS_I(inode),
  28                .attr_filter    = handler->flags,
  29                .name           = name,
  30                .namelen        = strlen(name),
  31                .value          = value,
  32                .valuelen       = size,
  33        };
  34        int                     error;
  35
  36        error = xfs_attr_get(&args);
  37        if (error)
  38                return error;
  39        return args.valuelen;
  40}
  41
  42static int
  43xfs_xattr_set(const struct xattr_handler *handler,
  44              struct user_namespace *mnt_userns, struct dentry *unused,
  45              struct inode *inode, const char *name, const void *value,
  46              size_t size, int flags)
  47{
  48        struct xfs_da_args      args = {
  49                .dp             = XFS_I(inode),
  50                .attr_filter    = handler->flags,
  51                .attr_flags     = flags,
  52                .name           = name,
  53                .namelen        = strlen(name),
  54                .value          = (void *)value,
  55                .valuelen       = size,
  56        };
  57        int                     error;
  58
  59        error = xfs_attr_set(&args);
  60        if (!error && (handler->flags & XFS_ATTR_ROOT))
  61                xfs_forget_acl(inode, name);
  62        return error;
  63}
  64
  65static const struct xattr_handler xfs_xattr_user_handler = {
  66        .prefix = XATTR_USER_PREFIX,
  67        .flags  = 0, /* no flags implies user namespace */
  68        .get    = xfs_xattr_get,
  69        .set    = xfs_xattr_set,
  70};
  71
  72static const struct xattr_handler xfs_xattr_trusted_handler = {
  73        .prefix = XATTR_TRUSTED_PREFIX,
  74        .flags  = XFS_ATTR_ROOT,
  75        .get    = xfs_xattr_get,
  76        .set    = xfs_xattr_set,
  77};
  78
  79static const struct xattr_handler xfs_xattr_security_handler = {
  80        .prefix = XATTR_SECURITY_PREFIX,
  81        .flags  = XFS_ATTR_SECURE,
  82        .get    = xfs_xattr_get,
  83        .set    = xfs_xattr_set,
  84};
  85
  86const struct xattr_handler *xfs_xattr_handlers[] = {
  87        &xfs_xattr_user_handler,
  88        &xfs_xattr_trusted_handler,
  89        &xfs_xattr_security_handler,
  90#ifdef CONFIG_XFS_POSIX_ACL
  91        &posix_acl_access_xattr_handler,
  92        &posix_acl_default_xattr_handler,
  93#endif
  94        NULL
  95};
  96
  97static void
  98__xfs_xattr_put_listent(
  99        struct xfs_attr_list_context *context,
 100        char *prefix,
 101        int prefix_len,
 102        unsigned char *name,
 103        int namelen)
 104{
 105        char *offset;
 106        int arraytop;
 107
 108        if (context->count < 0 || context->seen_enough)
 109                return;
 110
 111        if (!context->buffer)
 112                goto compute_size;
 113
 114        arraytop = context->count + prefix_len + namelen + 1;
 115        if (arraytop > context->firstu) {
 116                context->count = -1;    /* insufficient space */
 117                context->seen_enough = 1;
 118                return;
 119        }
 120        offset = context->buffer + context->count;
 121        strncpy(offset, prefix, prefix_len);
 122        offset += prefix_len;
 123        strncpy(offset, (char *)name, namelen);                 /* real name */
 124        offset += namelen;
 125        *offset = '\0';
 126
 127compute_size:
 128        context->count += prefix_len + namelen + 1;
 129        return;
 130}
 131
 132static void
 133xfs_xattr_put_listent(
 134        struct xfs_attr_list_context *context,
 135        int             flags,
 136        unsigned char   *name,
 137        int             namelen,
 138        int             valuelen)
 139{
 140        char *prefix;
 141        int prefix_len;
 142
 143        ASSERT(context->count >= 0);
 144
 145        if (flags & XFS_ATTR_ROOT) {
 146#ifdef CONFIG_XFS_POSIX_ACL
 147                if (namelen == SGI_ACL_FILE_SIZE &&
 148                    strncmp(name, SGI_ACL_FILE,
 149                            SGI_ACL_FILE_SIZE) == 0) {
 150                        __xfs_xattr_put_listent(
 151                                        context, XATTR_SYSTEM_PREFIX,
 152                                        XATTR_SYSTEM_PREFIX_LEN,
 153                                        XATTR_POSIX_ACL_ACCESS,
 154                                        strlen(XATTR_POSIX_ACL_ACCESS));
 155                } else if (namelen == SGI_ACL_DEFAULT_SIZE &&
 156                         strncmp(name, SGI_ACL_DEFAULT,
 157                                 SGI_ACL_DEFAULT_SIZE) == 0) {
 158                        __xfs_xattr_put_listent(
 159                                        context, XATTR_SYSTEM_PREFIX,
 160                                        XATTR_SYSTEM_PREFIX_LEN,
 161                                        XATTR_POSIX_ACL_DEFAULT,
 162                                        strlen(XATTR_POSIX_ACL_DEFAULT));
 163                }
 164#endif
 165
 166                /*
 167                 * Only show root namespace entries if we are actually allowed to
 168                 * see them.
 169                 */
 170                if (!capable(CAP_SYS_ADMIN))
 171                        return;
 172
 173                prefix = XATTR_TRUSTED_PREFIX;
 174                prefix_len = XATTR_TRUSTED_PREFIX_LEN;
 175        } else if (flags & XFS_ATTR_SECURE) {
 176                prefix = XATTR_SECURITY_PREFIX;
 177                prefix_len = XATTR_SECURITY_PREFIX_LEN;
 178        } else {
 179                prefix = XATTR_USER_PREFIX;
 180                prefix_len = XATTR_USER_PREFIX_LEN;
 181        }
 182
 183        __xfs_xattr_put_listent(context, prefix, prefix_len, name,
 184                                namelen);
 185        return;
 186}
 187
 188ssize_t
 189xfs_vn_listxattr(
 190        struct dentry   *dentry,
 191        char            *data,
 192        size_t          size)
 193{
 194        struct xfs_attr_list_context context;
 195        struct inode    *inode = d_inode(dentry);
 196        int             error;
 197
 198        /*
 199         * First read the regular on-disk attributes.
 200         */
 201        memset(&context, 0, sizeof(context));
 202        context.dp = XFS_I(inode);
 203        context.resynch = 1;
 204        context.buffer = size ? data : NULL;
 205        context.bufsize = size;
 206        context.firstu = context.bufsize;
 207        context.put_listent = xfs_xattr_put_listent;
 208
 209        error = xfs_attr_list(&context);
 210        if (error)
 211                return error;
 212        if (context.count < 0)
 213                return -ERANGE;
 214
 215        return context.count;
 216}
 217