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