0001
0002
0003
0004
0005
0006
0007
0008 #include <linux/quotaops.h>
0009 #include "ext4_jbd2.h"
0010 #include "ext4.h"
0011 #include "xattr.h"
0012 #include "acl.h"
0013
0014
0015
0016
0017 static struct posix_acl *
0018 ext4_acl_from_disk(const void *value, size_t size)
0019 {
0020 const char *end = (char *)value + size;
0021 int n, count;
0022 struct posix_acl *acl;
0023
0024 if (!value)
0025 return NULL;
0026 if (size < sizeof(ext4_acl_header))
0027 return ERR_PTR(-EINVAL);
0028 if (((ext4_acl_header *)value)->a_version !=
0029 cpu_to_le32(EXT4_ACL_VERSION))
0030 return ERR_PTR(-EINVAL);
0031 value = (char *)value + sizeof(ext4_acl_header);
0032 count = ext4_acl_count(size);
0033 if (count < 0)
0034 return ERR_PTR(-EINVAL);
0035 if (count == 0)
0036 return NULL;
0037 acl = posix_acl_alloc(count, GFP_NOFS);
0038 if (!acl)
0039 return ERR_PTR(-ENOMEM);
0040 for (n = 0; n < count; n++) {
0041 ext4_acl_entry *entry =
0042 (ext4_acl_entry *)value;
0043 if ((char *)value + sizeof(ext4_acl_entry_short) > end)
0044 goto fail;
0045 acl->a_entries[n].e_tag = le16_to_cpu(entry->e_tag);
0046 acl->a_entries[n].e_perm = le16_to_cpu(entry->e_perm);
0047
0048 switch (acl->a_entries[n].e_tag) {
0049 case ACL_USER_OBJ:
0050 case ACL_GROUP_OBJ:
0051 case ACL_MASK:
0052 case ACL_OTHER:
0053 value = (char *)value +
0054 sizeof(ext4_acl_entry_short);
0055 break;
0056
0057 case ACL_USER:
0058 value = (char *)value + sizeof(ext4_acl_entry);
0059 if ((char *)value > end)
0060 goto fail;
0061 acl->a_entries[n].e_uid =
0062 make_kuid(&init_user_ns,
0063 le32_to_cpu(entry->e_id));
0064 break;
0065 case ACL_GROUP:
0066 value = (char *)value + sizeof(ext4_acl_entry);
0067 if ((char *)value > end)
0068 goto fail;
0069 acl->a_entries[n].e_gid =
0070 make_kgid(&init_user_ns,
0071 le32_to_cpu(entry->e_id));
0072 break;
0073
0074 default:
0075 goto fail;
0076 }
0077 }
0078 if (value != end)
0079 goto fail;
0080 return acl;
0081
0082 fail:
0083 posix_acl_release(acl);
0084 return ERR_PTR(-EINVAL);
0085 }
0086
0087
0088
0089
0090 static void *
0091 ext4_acl_to_disk(const struct posix_acl *acl, size_t *size)
0092 {
0093 ext4_acl_header *ext_acl;
0094 char *e;
0095 size_t n;
0096
0097 *size = ext4_acl_size(acl->a_count);
0098 ext_acl = kmalloc(sizeof(ext4_acl_header) + acl->a_count *
0099 sizeof(ext4_acl_entry), GFP_NOFS);
0100 if (!ext_acl)
0101 return ERR_PTR(-ENOMEM);
0102 ext_acl->a_version = cpu_to_le32(EXT4_ACL_VERSION);
0103 e = (char *)ext_acl + sizeof(ext4_acl_header);
0104 for (n = 0; n < acl->a_count; n++) {
0105 const struct posix_acl_entry *acl_e = &acl->a_entries[n];
0106 ext4_acl_entry *entry = (ext4_acl_entry *)e;
0107 entry->e_tag = cpu_to_le16(acl_e->e_tag);
0108 entry->e_perm = cpu_to_le16(acl_e->e_perm);
0109 switch (acl_e->e_tag) {
0110 case ACL_USER:
0111 entry->e_id = cpu_to_le32(
0112 from_kuid(&init_user_ns, acl_e->e_uid));
0113 e += sizeof(ext4_acl_entry);
0114 break;
0115 case ACL_GROUP:
0116 entry->e_id = cpu_to_le32(
0117 from_kgid(&init_user_ns, acl_e->e_gid));
0118 e += sizeof(ext4_acl_entry);
0119 break;
0120
0121 case ACL_USER_OBJ:
0122 case ACL_GROUP_OBJ:
0123 case ACL_MASK:
0124 case ACL_OTHER:
0125 e += sizeof(ext4_acl_entry_short);
0126 break;
0127
0128 default:
0129 goto fail;
0130 }
0131 }
0132 return (char *)ext_acl;
0133
0134 fail:
0135 kfree(ext_acl);
0136 return ERR_PTR(-EINVAL);
0137 }
0138
0139
0140
0141
0142
0143
0144 struct posix_acl *
0145 ext4_get_acl(struct inode *inode, int type, bool rcu)
0146 {
0147 int name_index;
0148 char *value = NULL;
0149 struct posix_acl *acl;
0150 int retval;
0151
0152 if (rcu)
0153 return ERR_PTR(-ECHILD);
0154
0155 switch (type) {
0156 case ACL_TYPE_ACCESS:
0157 name_index = EXT4_XATTR_INDEX_POSIX_ACL_ACCESS;
0158 break;
0159 case ACL_TYPE_DEFAULT:
0160 name_index = EXT4_XATTR_INDEX_POSIX_ACL_DEFAULT;
0161 break;
0162 default:
0163 BUG();
0164 }
0165 retval = ext4_xattr_get(inode, name_index, "", NULL, 0);
0166 if (retval > 0) {
0167 value = kmalloc(retval, GFP_NOFS);
0168 if (!value)
0169 return ERR_PTR(-ENOMEM);
0170 retval = ext4_xattr_get(inode, name_index, "", value, retval);
0171 }
0172 if (retval > 0)
0173 acl = ext4_acl_from_disk(value, retval);
0174 else if (retval == -ENODATA || retval == -ENOSYS)
0175 acl = NULL;
0176 else
0177 acl = ERR_PTR(retval);
0178 kfree(value);
0179
0180 return acl;
0181 }
0182
0183
0184
0185
0186
0187
0188 static int
0189 __ext4_set_acl(handle_t *handle, struct inode *inode, int type,
0190 struct posix_acl *acl, int xattr_flags)
0191 {
0192 int name_index;
0193 void *value = NULL;
0194 size_t size = 0;
0195 int error;
0196
0197 switch (type) {
0198 case ACL_TYPE_ACCESS:
0199 name_index = EXT4_XATTR_INDEX_POSIX_ACL_ACCESS;
0200 break;
0201
0202 case ACL_TYPE_DEFAULT:
0203 name_index = EXT4_XATTR_INDEX_POSIX_ACL_DEFAULT;
0204 if (!S_ISDIR(inode->i_mode))
0205 return acl ? -EACCES : 0;
0206 break;
0207
0208 default:
0209 return -EINVAL;
0210 }
0211 if (acl) {
0212 value = ext4_acl_to_disk(acl, &size);
0213 if (IS_ERR(value))
0214 return (int)PTR_ERR(value);
0215 }
0216
0217 error = ext4_xattr_set_handle(handle, inode, name_index, "",
0218 value, size, xattr_flags);
0219
0220 kfree(value);
0221 if (!error)
0222 set_cached_acl(inode, type, acl);
0223
0224 return error;
0225 }
0226
0227 int
0228 ext4_set_acl(struct user_namespace *mnt_userns, struct inode *inode,
0229 struct posix_acl *acl, int type)
0230 {
0231 handle_t *handle;
0232 int error, credits, retries = 0;
0233 size_t acl_size = acl ? ext4_acl_size(acl->a_count) : 0;
0234 umode_t mode = inode->i_mode;
0235 int update_mode = 0;
0236
0237 error = dquot_initialize(inode);
0238 if (error)
0239 return error;
0240 retry:
0241 error = ext4_xattr_set_credits(inode, acl_size, false ,
0242 &credits);
0243 if (error)
0244 return error;
0245
0246 handle = ext4_journal_start(inode, EXT4_HT_XATTR, credits);
0247 if (IS_ERR(handle))
0248 return PTR_ERR(handle);
0249
0250 if ((type == ACL_TYPE_ACCESS) && acl) {
0251 error = posix_acl_update_mode(mnt_userns, inode, &mode, &acl);
0252 if (error)
0253 goto out_stop;
0254 if (mode != inode->i_mode)
0255 update_mode = 1;
0256 }
0257
0258 error = __ext4_set_acl(handle, inode, type, acl, 0 );
0259 if (!error && update_mode) {
0260 inode->i_mode = mode;
0261 inode->i_ctime = current_time(inode);
0262 error = ext4_mark_inode_dirty(handle, inode);
0263 }
0264 out_stop:
0265 ext4_journal_stop(handle);
0266 if (error == -ENOSPC && ext4_should_retry_alloc(inode->i_sb, &retries))
0267 goto retry;
0268 return error;
0269 }
0270
0271
0272
0273
0274
0275
0276
0277 int
0278 ext4_init_acl(handle_t *handle, struct inode *inode, struct inode *dir)
0279 {
0280 struct posix_acl *default_acl, *acl;
0281 int error;
0282
0283 error = posix_acl_create(dir, &inode->i_mode, &default_acl, &acl);
0284 if (error)
0285 return error;
0286
0287 if (default_acl) {
0288 error = __ext4_set_acl(handle, inode, ACL_TYPE_DEFAULT,
0289 default_acl, XATTR_CREATE);
0290 posix_acl_release(default_acl);
0291 } else {
0292 inode->i_default_acl = NULL;
0293 }
0294 if (acl) {
0295 if (!error)
0296 error = __ext4_set_acl(handle, inode, ACL_TYPE_ACCESS,
0297 acl, XATTR_CREATE);
0298 posix_acl_release(acl);
0299 } else {
0300 inode->i_acl = NULL;
0301 }
0302 return error;
0303 }