Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * acl.c
0004  *
0005  * Copyright (C) 2004, 2008 Oracle.  All rights reserved.
0006  *
0007  * CREDITS:
0008  * Lots of code in this file is copy from linux/fs/ext3/acl.c.
0009  * Copyright (C) 2001-2003 Andreas Gruenbacher, <agruen@suse.de>
0010  */
0011 
0012 #include <linux/init.h>
0013 #include <linux/module.h>
0014 #include <linux/slab.h>
0015 #include <linux/string.h>
0016 
0017 #include <cluster/masklog.h>
0018 
0019 #include "ocfs2.h"
0020 #include "alloc.h"
0021 #include "dlmglue.h"
0022 #include "file.h"
0023 #include "inode.h"
0024 #include "journal.h"
0025 #include "ocfs2_fs.h"
0026 
0027 #include "xattr.h"
0028 #include "acl.h"
0029 
0030 /*
0031  * Convert from xattr value to acl struct.
0032  */
0033 static struct posix_acl *ocfs2_acl_from_xattr(const void *value, size_t size)
0034 {
0035     int n, count;
0036     struct posix_acl *acl;
0037 
0038     if (!value)
0039         return NULL;
0040     if (size < sizeof(struct posix_acl_entry))
0041         return ERR_PTR(-EINVAL);
0042 
0043     count = size / sizeof(struct posix_acl_entry);
0044 
0045     acl = posix_acl_alloc(count, GFP_NOFS);
0046     if (!acl)
0047         return ERR_PTR(-ENOMEM);
0048     for (n = 0; n < count; n++) {
0049         struct ocfs2_acl_entry *entry =
0050             (struct ocfs2_acl_entry *)value;
0051 
0052         acl->a_entries[n].e_tag  = le16_to_cpu(entry->e_tag);
0053         acl->a_entries[n].e_perm = le16_to_cpu(entry->e_perm);
0054         switch(acl->a_entries[n].e_tag) {
0055         case ACL_USER:
0056             acl->a_entries[n].e_uid =
0057                 make_kuid(&init_user_ns,
0058                       le32_to_cpu(entry->e_id));
0059             break;
0060         case ACL_GROUP:
0061             acl->a_entries[n].e_gid =
0062                 make_kgid(&init_user_ns,
0063                       le32_to_cpu(entry->e_id));
0064             break;
0065         default:
0066             break;
0067         }
0068         value += sizeof(struct posix_acl_entry);
0069 
0070     }
0071     return acl;
0072 }
0073 
0074 /*
0075  * Convert acl struct to xattr value.
0076  */
0077 static void *ocfs2_acl_to_xattr(const struct posix_acl *acl, size_t *size)
0078 {
0079     struct ocfs2_acl_entry *entry = NULL;
0080     char *ocfs2_acl;
0081     size_t n;
0082 
0083     *size = acl->a_count * sizeof(struct posix_acl_entry);
0084 
0085     ocfs2_acl = kmalloc(*size, GFP_NOFS);
0086     if (!ocfs2_acl)
0087         return ERR_PTR(-ENOMEM);
0088 
0089     entry = (struct ocfs2_acl_entry *)ocfs2_acl;
0090     for (n = 0; n < acl->a_count; n++, entry++) {
0091         entry->e_tag  = cpu_to_le16(acl->a_entries[n].e_tag);
0092         entry->e_perm = cpu_to_le16(acl->a_entries[n].e_perm);
0093         switch(acl->a_entries[n].e_tag) {
0094         case ACL_USER:
0095             entry->e_id = cpu_to_le32(
0096                 from_kuid(&init_user_ns,
0097                       acl->a_entries[n].e_uid));
0098             break;
0099         case ACL_GROUP:
0100             entry->e_id = cpu_to_le32(
0101                 from_kgid(&init_user_ns,
0102                       acl->a_entries[n].e_gid));
0103             break;
0104         default:
0105             entry->e_id = cpu_to_le32(ACL_UNDEFINED_ID);
0106             break;
0107         }
0108     }
0109     return ocfs2_acl;
0110 }
0111 
0112 static struct posix_acl *ocfs2_get_acl_nolock(struct inode *inode,
0113                           int type,
0114                           struct buffer_head *di_bh)
0115 {
0116     int name_index;
0117     char *value = NULL;
0118     struct posix_acl *acl;
0119     int retval;
0120 
0121     switch (type) {
0122     case ACL_TYPE_ACCESS:
0123         name_index = OCFS2_XATTR_INDEX_POSIX_ACL_ACCESS;
0124         break;
0125     case ACL_TYPE_DEFAULT:
0126         name_index = OCFS2_XATTR_INDEX_POSIX_ACL_DEFAULT;
0127         break;
0128     default:
0129         return ERR_PTR(-EINVAL);
0130     }
0131 
0132     retval = ocfs2_xattr_get_nolock(inode, di_bh, name_index, "", NULL, 0);
0133     if (retval > 0) {
0134         value = kmalloc(retval, GFP_NOFS);
0135         if (!value)
0136             return ERR_PTR(-ENOMEM);
0137         retval = ocfs2_xattr_get_nolock(inode, di_bh, name_index,
0138                         "", value, retval);
0139     }
0140 
0141     if (retval > 0)
0142         acl = ocfs2_acl_from_xattr(value, retval);
0143     else if (retval == -ENODATA || retval == 0)
0144         acl = NULL;
0145     else
0146         acl = ERR_PTR(retval);
0147 
0148     kfree(value);
0149 
0150     return acl;
0151 }
0152 
0153 /*
0154  * Helper function to set i_mode in memory and disk. Some call paths
0155  * will not have di_bh or a journal handle to pass, in which case it
0156  * will create it's own.
0157  */
0158 static int ocfs2_acl_set_mode(struct inode *inode, struct buffer_head *di_bh,
0159                   handle_t *handle, umode_t new_mode)
0160 {
0161     int ret, commit_handle = 0;
0162     struct ocfs2_dinode *di;
0163 
0164     if (di_bh == NULL) {
0165         ret = ocfs2_read_inode_block(inode, &di_bh);
0166         if (ret) {
0167             mlog_errno(ret);
0168             goto out;
0169         }
0170     } else
0171         get_bh(di_bh);
0172 
0173     if (handle == NULL) {
0174         handle = ocfs2_start_trans(OCFS2_SB(inode->i_sb),
0175                        OCFS2_INODE_UPDATE_CREDITS);
0176         if (IS_ERR(handle)) {
0177             ret = PTR_ERR(handle);
0178             mlog_errno(ret);
0179             goto out_brelse;
0180         }
0181 
0182         commit_handle = 1;
0183     }
0184 
0185     di = (struct ocfs2_dinode *)di_bh->b_data;
0186     ret = ocfs2_journal_access_di(handle, INODE_CACHE(inode), di_bh,
0187                       OCFS2_JOURNAL_ACCESS_WRITE);
0188     if (ret) {
0189         mlog_errno(ret);
0190         goto out_commit;
0191     }
0192 
0193     inode->i_mode = new_mode;
0194     inode->i_ctime = current_time(inode);
0195     di->i_mode = cpu_to_le16(inode->i_mode);
0196     di->i_ctime = cpu_to_le64(inode->i_ctime.tv_sec);
0197     di->i_ctime_nsec = cpu_to_le32(inode->i_ctime.tv_nsec);
0198     ocfs2_update_inode_fsync_trans(handle, inode, 0);
0199 
0200     ocfs2_journal_dirty(handle, di_bh);
0201 
0202 out_commit:
0203     if (commit_handle)
0204         ocfs2_commit_trans(OCFS2_SB(inode->i_sb), handle);
0205 out_brelse:
0206     brelse(di_bh);
0207 out:
0208     return ret;
0209 }
0210 
0211 /*
0212  * Set the access or default ACL of an inode.
0213  */
0214 static int ocfs2_set_acl(handle_t *handle,
0215              struct inode *inode,
0216              struct buffer_head *di_bh,
0217              int type,
0218              struct posix_acl *acl,
0219              struct ocfs2_alloc_context *meta_ac,
0220              struct ocfs2_alloc_context *data_ac)
0221 {
0222     int name_index;
0223     void *value = NULL;
0224     size_t size = 0;
0225     int ret;
0226 
0227     if (S_ISLNK(inode->i_mode))
0228         return -EOPNOTSUPP;
0229 
0230     switch (type) {
0231     case ACL_TYPE_ACCESS:
0232         name_index = OCFS2_XATTR_INDEX_POSIX_ACL_ACCESS;
0233         break;
0234     case ACL_TYPE_DEFAULT:
0235         name_index = OCFS2_XATTR_INDEX_POSIX_ACL_DEFAULT;
0236         if (!S_ISDIR(inode->i_mode))
0237             return acl ? -EACCES : 0;
0238         break;
0239     default:
0240         return -EINVAL;
0241     }
0242 
0243     if (acl) {
0244         value = ocfs2_acl_to_xattr(acl, &size);
0245         if (IS_ERR(value))
0246             return (int)PTR_ERR(value);
0247     }
0248 
0249     if (handle)
0250         ret = ocfs2_xattr_set_handle(handle, inode, di_bh, name_index,
0251                          "", value, size, 0,
0252                          meta_ac, data_ac);
0253     else
0254         ret = ocfs2_xattr_set(inode, name_index, "", value, size, 0);
0255 
0256     kfree(value);
0257     if (!ret)
0258         set_cached_acl(inode, type, acl);
0259 
0260     return ret;
0261 }
0262 
0263 int ocfs2_iop_set_acl(struct user_namespace *mnt_userns, struct inode *inode,
0264               struct posix_acl *acl, int type)
0265 {
0266     struct buffer_head *bh = NULL;
0267     int status, had_lock;
0268     struct ocfs2_lock_holder oh;
0269 
0270     had_lock = ocfs2_inode_lock_tracker(inode, &bh, 1, &oh);
0271     if (had_lock < 0)
0272         return had_lock;
0273     if (type == ACL_TYPE_ACCESS && acl) {
0274         umode_t mode;
0275 
0276         status = posix_acl_update_mode(&init_user_ns, inode, &mode,
0277                            &acl);
0278         if (status)
0279             goto unlock;
0280 
0281         status = ocfs2_acl_set_mode(inode, bh, NULL, mode);
0282         if (status)
0283             goto unlock;
0284     }
0285     status = ocfs2_set_acl(NULL, inode, bh, type, acl, NULL, NULL);
0286 unlock:
0287     ocfs2_inode_unlock_tracker(inode, 1, &oh, had_lock);
0288     brelse(bh);
0289     return status;
0290 }
0291 
0292 struct posix_acl *ocfs2_iop_get_acl(struct inode *inode, int type, bool rcu)
0293 {
0294     struct ocfs2_super *osb;
0295     struct buffer_head *di_bh = NULL;
0296     struct posix_acl *acl;
0297     int had_lock;
0298     struct ocfs2_lock_holder oh;
0299 
0300     if (rcu)
0301         return ERR_PTR(-ECHILD);
0302 
0303     osb = OCFS2_SB(inode->i_sb);
0304     if (!(osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL))
0305         return NULL;
0306 
0307     had_lock = ocfs2_inode_lock_tracker(inode, &di_bh, 0, &oh);
0308     if (had_lock < 0)
0309         return ERR_PTR(had_lock);
0310 
0311     down_read(&OCFS2_I(inode)->ip_xattr_sem);
0312     acl = ocfs2_get_acl_nolock(inode, type, di_bh);
0313     up_read(&OCFS2_I(inode)->ip_xattr_sem);
0314 
0315     ocfs2_inode_unlock_tracker(inode, 0, &oh, had_lock);
0316     brelse(di_bh);
0317     return acl;
0318 }
0319 
0320 int ocfs2_acl_chmod(struct inode *inode, struct buffer_head *bh)
0321 {
0322     struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
0323     struct posix_acl *acl;
0324     int ret;
0325 
0326     if (S_ISLNK(inode->i_mode))
0327         return -EOPNOTSUPP;
0328 
0329     if (!(osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL))
0330         return 0;
0331 
0332     down_read(&OCFS2_I(inode)->ip_xattr_sem);
0333     acl = ocfs2_get_acl_nolock(inode, ACL_TYPE_ACCESS, bh);
0334     up_read(&OCFS2_I(inode)->ip_xattr_sem);
0335     if (IS_ERR_OR_NULL(acl))
0336         return PTR_ERR_OR_ZERO(acl);
0337     ret = __posix_acl_chmod(&acl, GFP_KERNEL, inode->i_mode);
0338     if (ret)
0339         return ret;
0340     ret = ocfs2_set_acl(NULL, inode, NULL, ACL_TYPE_ACCESS,
0341                 acl, NULL, NULL);
0342     posix_acl_release(acl);
0343     return ret;
0344 }
0345 
0346 /*
0347  * Initialize the ACLs of a new inode. If parent directory has default ACL,
0348  * then clone to new inode. Called from ocfs2_mknod.
0349  */
0350 int ocfs2_init_acl(handle_t *handle,
0351            struct inode *inode,
0352            struct inode *dir,
0353            struct buffer_head *di_bh,
0354            struct buffer_head *dir_bh,
0355            struct ocfs2_alloc_context *meta_ac,
0356            struct ocfs2_alloc_context *data_ac)
0357 {
0358     struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
0359     struct posix_acl *acl = NULL;
0360     int ret = 0, ret2;
0361     umode_t mode;
0362 
0363     if (!S_ISLNK(inode->i_mode)) {
0364         if (osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL) {
0365             down_read(&OCFS2_I(dir)->ip_xattr_sem);
0366             acl = ocfs2_get_acl_nolock(dir, ACL_TYPE_DEFAULT,
0367                            dir_bh);
0368             up_read(&OCFS2_I(dir)->ip_xattr_sem);
0369             if (IS_ERR(acl))
0370                 return PTR_ERR(acl);
0371         }
0372         if (!acl) {
0373             mode = inode->i_mode & ~current_umask();
0374             ret = ocfs2_acl_set_mode(inode, di_bh, handle, mode);
0375             if (ret) {
0376                 mlog_errno(ret);
0377                 goto cleanup;
0378             }
0379         }
0380     }
0381     if ((osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL) && acl) {
0382         if (S_ISDIR(inode->i_mode)) {
0383             ret = ocfs2_set_acl(handle, inode, di_bh,
0384                         ACL_TYPE_DEFAULT, acl,
0385                         meta_ac, data_ac);
0386             if (ret)
0387                 goto cleanup;
0388         }
0389         mode = inode->i_mode;
0390         ret = __posix_acl_create(&acl, GFP_NOFS, &mode);
0391         if (ret < 0)
0392             return ret;
0393 
0394         ret2 = ocfs2_acl_set_mode(inode, di_bh, handle, mode);
0395         if (ret2) {
0396             mlog_errno(ret2);
0397             ret = ret2;
0398             goto cleanup;
0399         }
0400         if (ret > 0) {
0401             ret = ocfs2_set_acl(handle, inode,
0402                         di_bh, ACL_TYPE_ACCESS,
0403                         acl, meta_ac, data_ac);
0404         }
0405     }
0406 cleanup:
0407     posix_acl_release(acl);
0408     return ret;
0409 }