linux/fs/xfs/xfs_acl.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Copyright (c) 2008, Christoph Hellwig
   4 * All Rights Reserved.
   5 */
   6#include "xfs.h"
   7#include "xfs_shared.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_inode.h"
  13#include "xfs_attr.h"
  14#include "xfs_trace.h"
  15#include "xfs_error.h"
  16#include "xfs_acl.h"
  17
  18#include <linux/posix_acl_xattr.h>
  19
  20/*
  21 * Locking scheme:
  22 *  - all ACL updates are protected by inode->i_mutex, which is taken before
  23 *    calling into this file.
  24 */
  25
  26STATIC struct posix_acl *
  27xfs_acl_from_disk(
  28        struct xfs_mount        *mp,
  29        const struct xfs_acl    *aclp,
  30        int                     len,
  31        int                     max_entries)
  32{
  33        struct posix_acl_entry *acl_e;
  34        struct posix_acl *acl;
  35        const struct xfs_acl_entry *ace;
  36        unsigned int count, i;
  37
  38        if (len < sizeof(*aclp)) {
  39                XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, aclp,
  40                                len);
  41                return ERR_PTR(-EFSCORRUPTED);
  42        }
  43
  44        count = be32_to_cpu(aclp->acl_cnt);
  45        if (count > max_entries || XFS_ACL_SIZE(count) != len) {
  46                XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, aclp,
  47                                len);
  48                return ERR_PTR(-EFSCORRUPTED);
  49        }
  50
  51        acl = posix_acl_alloc(count, GFP_KERNEL);
  52        if (!acl)
  53                return ERR_PTR(-ENOMEM);
  54
  55        for (i = 0; i < count; i++) {
  56                acl_e = &acl->a_entries[i];
  57                ace = &aclp->acl_entry[i];
  58
  59                /*
  60                 * The tag is 32 bits on disk and 16 bits in core.
  61                 *
  62                 * Because every access to it goes through the core
  63                 * format first this is not a problem.
  64                 */
  65                acl_e->e_tag = be32_to_cpu(ace->ae_tag);
  66                acl_e->e_perm = be16_to_cpu(ace->ae_perm);
  67
  68                switch (acl_e->e_tag) {
  69                case ACL_USER:
  70                        acl_e->e_uid = xfs_uid_to_kuid(be32_to_cpu(ace->ae_id));
  71                        break;
  72                case ACL_GROUP:
  73                        acl_e->e_gid = xfs_gid_to_kgid(be32_to_cpu(ace->ae_id));
  74                        break;
  75                case ACL_USER_OBJ:
  76                case ACL_GROUP_OBJ:
  77                case ACL_MASK:
  78                case ACL_OTHER:
  79                        break;
  80                default:
  81                        goto fail;
  82                }
  83        }
  84        return acl;
  85
  86fail:
  87        posix_acl_release(acl);
  88        return ERR_PTR(-EINVAL);
  89}
  90
  91STATIC void
  92xfs_acl_to_disk(struct xfs_acl *aclp, const struct posix_acl *acl)
  93{
  94        const struct posix_acl_entry *acl_e;
  95        struct xfs_acl_entry *ace;
  96        int i;
  97
  98        aclp->acl_cnt = cpu_to_be32(acl->a_count);
  99        for (i = 0; i < acl->a_count; i++) {
 100                ace = &aclp->acl_entry[i];
 101                acl_e = &acl->a_entries[i];
 102
 103                ace->ae_tag = cpu_to_be32(acl_e->e_tag);
 104                switch (acl_e->e_tag) {
 105                case ACL_USER:
 106                        ace->ae_id = cpu_to_be32(xfs_kuid_to_uid(acl_e->e_uid));
 107                        break;
 108                case ACL_GROUP:
 109                        ace->ae_id = cpu_to_be32(xfs_kgid_to_gid(acl_e->e_gid));
 110                        break;
 111                default:
 112                        ace->ae_id = cpu_to_be32(ACL_UNDEFINED_ID);
 113                        break;
 114                }
 115
 116                ace->ae_perm = cpu_to_be16(acl_e->e_perm);
 117        }
 118}
 119
 120struct posix_acl *
 121xfs_get_acl(struct inode *inode, int type)
 122{
 123        struct xfs_inode *ip = XFS_I(inode);
 124        struct posix_acl *acl = NULL;
 125        struct xfs_acl *xfs_acl = NULL;
 126        unsigned char *ea_name;
 127        int error;
 128        int len;
 129
 130        trace_xfs_get_acl(ip);
 131
 132        switch (type) {
 133        case ACL_TYPE_ACCESS:
 134                ea_name = SGI_ACL_FILE;
 135                break;
 136        case ACL_TYPE_DEFAULT:
 137                ea_name = SGI_ACL_DEFAULT;
 138                break;
 139        default:
 140                BUG();
 141        }
 142
 143        /*
 144         * If we have a cached ACLs value just return it, not need to
 145         * go out to the disk.
 146         */
 147        len = XFS_ACL_MAX_SIZE(ip->i_mount);
 148        error = xfs_attr_get(ip, ea_name, strlen(ea_name),
 149                                (unsigned char **)&xfs_acl, &len,
 150                                ATTR_ALLOC | ATTR_ROOT);
 151        if (error) {
 152                /*
 153                 * If the attribute doesn't exist make sure we have a negative
 154                 * cache entry, for any other error assume it is transient.
 155                 */
 156                if (error != -ENOATTR)
 157                        acl = ERR_PTR(error);
 158        } else  {
 159                acl = xfs_acl_from_disk(ip->i_mount, xfs_acl, len,
 160                                        XFS_ACL_MAX_ENTRIES(ip->i_mount));
 161                kmem_free(xfs_acl);
 162        }
 163        return acl;
 164}
 165
 166int
 167__xfs_set_acl(struct inode *inode, struct posix_acl *acl, int type)
 168{
 169        struct xfs_inode *ip = XFS_I(inode);
 170        unsigned char *ea_name;
 171        int error;
 172
 173        switch (type) {
 174        case ACL_TYPE_ACCESS:
 175                ea_name = SGI_ACL_FILE;
 176                break;
 177        case ACL_TYPE_DEFAULT:
 178                if (!S_ISDIR(inode->i_mode))
 179                        return acl ? -EACCES : 0;
 180                ea_name = SGI_ACL_DEFAULT;
 181                break;
 182        default:
 183                return -EINVAL;
 184        }
 185
 186        if (acl) {
 187                struct xfs_acl *xfs_acl;
 188                int len = XFS_ACL_MAX_SIZE(ip->i_mount);
 189
 190                xfs_acl = kmem_zalloc_large(len, 0);
 191                if (!xfs_acl)
 192                        return -ENOMEM;
 193
 194                xfs_acl_to_disk(xfs_acl, acl);
 195
 196                /* subtract away the unused acl entries */
 197                len -= sizeof(struct xfs_acl_entry) *
 198                         (XFS_ACL_MAX_ENTRIES(ip->i_mount) - acl->a_count);
 199
 200                error = xfs_attr_set(ip, ea_name, strlen(ea_name),
 201                                     (unsigned char *)xfs_acl, len, ATTR_ROOT);
 202
 203                kmem_free(xfs_acl);
 204        } else {
 205                /*
 206                 * A NULL ACL argument means we want to remove the ACL.
 207                 */
 208                error = xfs_attr_remove(ip, ea_name,
 209                                        strlen(ea_name),
 210                                        ATTR_ROOT);
 211
 212                /*
 213                 * If the attribute didn't exist to start with that's fine.
 214                 */
 215                if (error == -ENOATTR)
 216                        error = 0;
 217        }
 218
 219        if (!error)
 220                set_cached_acl(inode, type, acl);
 221        return error;
 222}
 223
 224static int
 225xfs_set_mode(struct inode *inode, umode_t mode)
 226{
 227        int error = 0;
 228
 229        if (mode != inode->i_mode) {
 230                struct iattr iattr;
 231
 232                iattr.ia_valid = ATTR_MODE | ATTR_CTIME;
 233                iattr.ia_mode = mode;
 234                iattr.ia_ctime = current_time(inode);
 235
 236                error = xfs_setattr_nonsize(XFS_I(inode), &iattr, XFS_ATTR_NOACL);
 237        }
 238
 239        return error;
 240}
 241
 242int
 243xfs_set_acl(struct inode *inode, struct posix_acl *acl, int type)
 244{
 245        umode_t mode;
 246        bool set_mode = false;
 247        int error = 0;
 248
 249        if (!acl)
 250                goto set_acl;
 251
 252        error = -E2BIG;
 253        if (acl->a_count > XFS_ACL_MAX_ENTRIES(XFS_M(inode->i_sb)))
 254                return error;
 255
 256        if (type == ACL_TYPE_ACCESS) {
 257                error = posix_acl_update_mode(inode, &mode, &acl);
 258                if (error)
 259                        return error;
 260                set_mode = true;
 261        }
 262
 263 set_acl:
 264        error =  __xfs_set_acl(inode, acl, type);
 265        if (error)
 266                return error;
 267
 268        /*
 269         * We set the mode after successfully updating the ACL xattr because the
 270         * xattr update can fail at ENOSPC and we don't want to change the mode
 271         * if the ACL update hasn't been applied.
 272         */
 273        if (set_mode)
 274                error = xfs_set_mode(inode, mode);
 275
 276        return error;
 277}
 278