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_format.h"
   9#include "xfs_log_format.h"
  10#include "xfs_trans_resv.h"
  11#include "xfs_mount.h"
  12#include "xfs_da_format.h"
  13#include "xfs_inode.h"
  14#include "xfs_attr.h"
  15#include "xfs_attr_leaf.h"
  16#include "xfs_acl.h"
  17
  18#include <linux/posix_acl_xattr.h>
  19#include <linux/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        int xflags = handler->flags;
  27        struct xfs_inode *ip = XFS_I(inode);
  28        int error, asize = size;
  29
  30        /* Convert Linux syscall to XFS internal ATTR flags */
  31        if (!size) {
  32                xflags |= ATTR_KERNOVAL;
  33                value = NULL;
  34        }
  35
  36        error = xfs_attr_get(ip, (unsigned char *)name, value, &asize, xflags);
  37        if (error)
  38                return error;
  39        return asize;
  40}
  41
  42void
  43xfs_forget_acl(
  44        struct inode            *inode,
  45        const char              *name,
  46        int                     xflags)
  47{
  48        /*
  49         * Invalidate any cached ACLs if the user has bypassed the ACL
  50         * interface. We don't validate the content whatsoever so it is caller
  51         * responsibility to provide data in valid format and ensure i_mode is
  52         * consistent.
  53         */
  54        if (xflags & ATTR_ROOT) {
  55#ifdef CONFIG_XFS_POSIX_ACL
  56                if (!strcmp(name, SGI_ACL_FILE))
  57                        forget_cached_acl(inode, ACL_TYPE_ACCESS);
  58                else if (!strcmp(name, SGI_ACL_DEFAULT))
  59                        forget_cached_acl(inode, ACL_TYPE_DEFAULT);
  60#endif
  61        }
  62}
  63
  64static int
  65xfs_xattr_set(const struct xattr_handler *handler, struct dentry *unused,
  66                struct inode *inode, const char *name, const void *value,
  67                size_t size, int flags)
  68{
  69        int                     xflags = handler->flags;
  70        struct xfs_inode        *ip = XFS_I(inode);
  71        int                     error;
  72
  73        /* Convert Linux syscall to XFS internal ATTR flags */
  74        if (flags & XATTR_CREATE)
  75                xflags |= ATTR_CREATE;
  76        if (flags & XATTR_REPLACE)
  77                xflags |= ATTR_REPLACE;
  78
  79        if (!value)
  80                return xfs_attr_remove(ip, (unsigned char *)name, xflags);
  81        error = xfs_attr_set(ip, (unsigned char *)name,
  82                                (void *)value, size, xflags);
  83        if (!error)
  84                xfs_forget_acl(inode, name, xflags);
  85
  86        return error;
  87}
  88
  89static const struct xattr_handler xfs_xattr_user_handler = {
  90        .prefix = XATTR_USER_PREFIX,
  91        .flags  = 0, /* no flags implies user namespace */
  92        .get    = xfs_xattr_get,
  93        .set    = xfs_xattr_set,
  94};
  95
  96static const struct xattr_handler xfs_xattr_trusted_handler = {
  97        .prefix = XATTR_TRUSTED_PREFIX,
  98        .flags  = ATTR_ROOT,
  99        .get    = xfs_xattr_get,
 100        .set    = xfs_xattr_set,
 101};
 102
 103static const struct xattr_handler xfs_xattr_security_handler = {
 104        .prefix = XATTR_SECURITY_PREFIX,
 105        .flags  = ATTR_SECURE,
 106        .get    = xfs_xattr_get,
 107        .set    = xfs_xattr_set,
 108};
 109
 110const struct xattr_handler *xfs_xattr_handlers[] = {
 111        &xfs_xattr_user_handler,
 112        &xfs_xattr_trusted_handler,
 113        &xfs_xattr_security_handler,
 114#ifdef CONFIG_XFS_POSIX_ACL
 115        &posix_acl_access_xattr_handler,
 116        &posix_acl_default_xattr_handler,
 117#endif
 118        NULL
 119};
 120
 121static void
 122__xfs_xattr_put_listent(
 123        struct xfs_attr_list_context *context,
 124        char *prefix,
 125        int prefix_len,
 126        unsigned char *name,
 127        int namelen)
 128{
 129        char *offset;
 130        int arraytop;
 131
 132        if (context->count < 0 || context->seen_enough)
 133                return;
 134
 135        if (!context->alist)
 136                goto compute_size;
 137
 138        arraytop = context->count + prefix_len + namelen + 1;
 139        if (arraytop > context->firstu) {
 140                context->count = -1;    /* insufficient space */
 141                context->seen_enough = 1;
 142                return;
 143        }
 144        offset = (char *)context->alist + context->count;
 145        strncpy(offset, prefix, prefix_len);
 146        offset += prefix_len;
 147        strncpy(offset, (char *)name, namelen);                 /* real name */
 148        offset += namelen;
 149        *offset = '\0';
 150
 151compute_size:
 152        context->count += prefix_len + namelen + 1;
 153        return;
 154}
 155
 156static void
 157xfs_xattr_put_listent(
 158        struct xfs_attr_list_context *context,
 159        int             flags,
 160        unsigned char   *name,
 161        int             namelen,
 162        int             valuelen)
 163{
 164        char *prefix;
 165        int prefix_len;
 166
 167        ASSERT(context->count >= 0);
 168
 169        if (flags & XFS_ATTR_ROOT) {
 170#ifdef CONFIG_XFS_POSIX_ACL
 171                if (namelen == SGI_ACL_FILE_SIZE &&
 172                    strncmp(name, SGI_ACL_FILE,
 173                            SGI_ACL_FILE_SIZE) == 0) {
 174                        __xfs_xattr_put_listent(
 175                                        context, XATTR_SYSTEM_PREFIX,
 176                                        XATTR_SYSTEM_PREFIX_LEN,
 177                                        XATTR_POSIX_ACL_ACCESS,
 178                                        strlen(XATTR_POSIX_ACL_ACCESS));
 179                } else if (namelen == SGI_ACL_DEFAULT_SIZE &&
 180                         strncmp(name, SGI_ACL_DEFAULT,
 181                                 SGI_ACL_DEFAULT_SIZE) == 0) {
 182                        __xfs_xattr_put_listent(
 183                                        context, XATTR_SYSTEM_PREFIX,
 184                                        XATTR_SYSTEM_PREFIX_LEN,
 185                                        XATTR_POSIX_ACL_DEFAULT,
 186                                        strlen(XATTR_POSIX_ACL_DEFAULT));
 187                }
 188#endif
 189
 190                /*
 191                 * Only show root namespace entries if we are actually allowed to
 192                 * see them.
 193                 */
 194                if (!capable(CAP_SYS_ADMIN))
 195                        return;
 196
 197                prefix = XATTR_TRUSTED_PREFIX;
 198                prefix_len = XATTR_TRUSTED_PREFIX_LEN;
 199        } else if (flags & XFS_ATTR_SECURE) {
 200                prefix = XATTR_SECURITY_PREFIX;
 201                prefix_len = XATTR_SECURITY_PREFIX_LEN;
 202        } else {
 203                prefix = XATTR_USER_PREFIX;
 204                prefix_len = XATTR_USER_PREFIX_LEN;
 205        }
 206
 207        __xfs_xattr_put_listent(context, prefix, prefix_len, name,
 208                                namelen);
 209        return;
 210}
 211
 212ssize_t
 213xfs_vn_listxattr(
 214        struct dentry   *dentry,
 215        char            *data,
 216        size_t          size)
 217{
 218        struct xfs_attr_list_context context;
 219        struct attrlist_cursor_kern cursor = { 0 };
 220        struct inode    *inode = d_inode(dentry);
 221        int             error;
 222
 223        /*
 224         * First read the regular on-disk attributes.
 225         */
 226        memset(&context, 0, sizeof(context));
 227        context.dp = XFS_I(inode);
 228        context.cursor = &cursor;
 229        context.resynch = 1;
 230        context.alist = size ? data : NULL;
 231        context.bufsize = size;
 232        context.firstu = context.bufsize;
 233        context.put_listent = xfs_xattr_put_listent;
 234
 235        error = xfs_attr_list_int(&context);
 236        if (error)
 237                return error;
 238        if (context.count < 0)
 239                return -ERANGE;
 240
 241        return context.count;
 242}
 243