0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
0013
0014 #include <linux/kernel.h>
0015 #include <linux/slab.h>
0016 #include <linux/fs.h>
0017 #include <linux/sched.h>
0018 #include <linux/time.h>
0019 #include <linux/crc32.h>
0020 #include <linux/jffs2.h>
0021 #include <linux/xattr.h>
0022 #include <linux/posix_acl_xattr.h>
0023 #include <linux/mtd/mtd.h>
0024 #include "nodelist.h"
0025
0026 static size_t jffs2_acl_size(int count)
0027 {
0028 if (count <= 4) {
0029 return sizeof(struct jffs2_acl_header)
0030 + count * sizeof(struct jffs2_acl_entry_short);
0031 } else {
0032 return sizeof(struct jffs2_acl_header)
0033 + 4 * sizeof(struct jffs2_acl_entry_short)
0034 + (count - 4) * sizeof(struct jffs2_acl_entry);
0035 }
0036 }
0037
0038 static int jffs2_acl_count(size_t size)
0039 {
0040 size_t s;
0041
0042 size -= sizeof(struct jffs2_acl_header);
0043 if (size < 4 * sizeof(struct jffs2_acl_entry_short)) {
0044 if (size % sizeof(struct jffs2_acl_entry_short))
0045 return -1;
0046 return size / sizeof(struct jffs2_acl_entry_short);
0047 } else {
0048 s = size - 4 * sizeof(struct jffs2_acl_entry_short);
0049 if (s % sizeof(struct jffs2_acl_entry))
0050 return -1;
0051 return s / sizeof(struct jffs2_acl_entry) + 4;
0052 }
0053 }
0054
0055 static struct posix_acl *jffs2_acl_from_medium(void *value, size_t size)
0056 {
0057 void *end = value + size;
0058 struct jffs2_acl_header *header = value;
0059 struct jffs2_acl_entry *entry;
0060 struct posix_acl *acl;
0061 uint32_t ver;
0062 int i, count;
0063
0064 if (!value)
0065 return NULL;
0066 if (size < sizeof(struct jffs2_acl_header))
0067 return ERR_PTR(-EINVAL);
0068 ver = je32_to_cpu(header->a_version);
0069 if (ver != JFFS2_ACL_VERSION) {
0070 JFFS2_WARNING("Invalid ACL version. (=%u)\n", ver);
0071 return ERR_PTR(-EINVAL);
0072 }
0073
0074 value += sizeof(struct jffs2_acl_header);
0075 count = jffs2_acl_count(size);
0076 if (count < 0)
0077 return ERR_PTR(-EINVAL);
0078 if (count == 0)
0079 return NULL;
0080
0081 acl = posix_acl_alloc(count, GFP_KERNEL);
0082 if (!acl)
0083 return ERR_PTR(-ENOMEM);
0084
0085 for (i=0; i < count; i++) {
0086 entry = value;
0087 if (value + sizeof(struct jffs2_acl_entry_short) > end)
0088 goto fail;
0089 acl->a_entries[i].e_tag = je16_to_cpu(entry->e_tag);
0090 acl->a_entries[i].e_perm = je16_to_cpu(entry->e_perm);
0091 switch (acl->a_entries[i].e_tag) {
0092 case ACL_USER_OBJ:
0093 case ACL_GROUP_OBJ:
0094 case ACL_MASK:
0095 case ACL_OTHER:
0096 value += sizeof(struct jffs2_acl_entry_short);
0097 break;
0098
0099 case ACL_USER:
0100 value += sizeof(struct jffs2_acl_entry);
0101 if (value > end)
0102 goto fail;
0103 acl->a_entries[i].e_uid =
0104 make_kuid(&init_user_ns,
0105 je32_to_cpu(entry->e_id));
0106 break;
0107 case ACL_GROUP:
0108 value += sizeof(struct jffs2_acl_entry);
0109 if (value > end)
0110 goto fail;
0111 acl->a_entries[i].e_gid =
0112 make_kgid(&init_user_ns,
0113 je32_to_cpu(entry->e_id));
0114 break;
0115
0116 default:
0117 goto fail;
0118 }
0119 }
0120 if (value != end)
0121 goto fail;
0122 return acl;
0123 fail:
0124 posix_acl_release(acl);
0125 return ERR_PTR(-EINVAL);
0126 }
0127
0128 static void *jffs2_acl_to_medium(const struct posix_acl *acl, size_t *size)
0129 {
0130 struct jffs2_acl_header *header;
0131 struct jffs2_acl_entry *entry;
0132 void *e;
0133 size_t i;
0134
0135 *size = jffs2_acl_size(acl->a_count);
0136 header = kmalloc(struct_size(header, a_entries, acl->a_count),
0137 GFP_KERNEL);
0138 if (!header)
0139 return ERR_PTR(-ENOMEM);
0140 header->a_version = cpu_to_je32(JFFS2_ACL_VERSION);
0141 e = header + 1;
0142 for (i=0; i < acl->a_count; i++) {
0143 const struct posix_acl_entry *acl_e = &acl->a_entries[i];
0144 entry = e;
0145 entry->e_tag = cpu_to_je16(acl_e->e_tag);
0146 entry->e_perm = cpu_to_je16(acl_e->e_perm);
0147 switch(acl_e->e_tag) {
0148 case ACL_USER:
0149 entry->e_id = cpu_to_je32(
0150 from_kuid(&init_user_ns, acl_e->e_uid));
0151 e += sizeof(struct jffs2_acl_entry);
0152 break;
0153 case ACL_GROUP:
0154 entry->e_id = cpu_to_je32(
0155 from_kgid(&init_user_ns, acl_e->e_gid));
0156 e += sizeof(struct jffs2_acl_entry);
0157 break;
0158
0159 case ACL_USER_OBJ:
0160 case ACL_GROUP_OBJ:
0161 case ACL_MASK:
0162 case ACL_OTHER:
0163 e += sizeof(struct jffs2_acl_entry_short);
0164 break;
0165
0166 default:
0167 goto fail;
0168 }
0169 }
0170 return header;
0171 fail:
0172 kfree(header);
0173 return ERR_PTR(-EINVAL);
0174 }
0175
0176 struct posix_acl *jffs2_get_acl(struct inode *inode, int type, bool rcu)
0177 {
0178 struct posix_acl *acl;
0179 char *value = NULL;
0180 int rc, xprefix;
0181
0182 if (rcu)
0183 return ERR_PTR(-ECHILD);
0184
0185 switch (type) {
0186 case ACL_TYPE_ACCESS:
0187 xprefix = JFFS2_XPREFIX_ACL_ACCESS;
0188 break;
0189 case ACL_TYPE_DEFAULT:
0190 xprefix = JFFS2_XPREFIX_ACL_DEFAULT;
0191 break;
0192 default:
0193 BUG();
0194 }
0195 rc = do_jffs2_getxattr(inode, xprefix, "", NULL, 0);
0196 if (rc > 0) {
0197 value = kmalloc(rc, GFP_KERNEL);
0198 if (!value)
0199 return ERR_PTR(-ENOMEM);
0200 rc = do_jffs2_getxattr(inode, xprefix, "", value, rc);
0201 }
0202 if (rc > 0) {
0203 acl = jffs2_acl_from_medium(value, rc);
0204 } else if (rc == -ENODATA || rc == -ENOSYS) {
0205 acl = NULL;
0206 } else {
0207 acl = ERR_PTR(rc);
0208 }
0209 kfree(value);
0210 return acl;
0211 }
0212
0213 static int __jffs2_set_acl(struct inode *inode, int xprefix, struct posix_acl *acl)
0214 {
0215 char *value = NULL;
0216 size_t size = 0;
0217 int rc;
0218
0219 if (acl) {
0220 value = jffs2_acl_to_medium(acl, &size);
0221 if (IS_ERR(value))
0222 return PTR_ERR(value);
0223 }
0224 rc = do_jffs2_setxattr(inode, xprefix, "", value, size, 0);
0225 if (!value && rc == -ENODATA)
0226 rc = 0;
0227 kfree(value);
0228
0229 return rc;
0230 }
0231
0232 int jffs2_set_acl(struct user_namespace *mnt_userns, struct inode *inode,
0233 struct posix_acl *acl, int type)
0234 {
0235 int rc, xprefix;
0236
0237 switch (type) {
0238 case ACL_TYPE_ACCESS:
0239 xprefix = JFFS2_XPREFIX_ACL_ACCESS;
0240 if (acl) {
0241 umode_t mode;
0242
0243 rc = posix_acl_update_mode(&init_user_ns, inode, &mode,
0244 &acl);
0245 if (rc)
0246 return rc;
0247 if (inode->i_mode != mode) {
0248 struct iattr attr;
0249
0250 attr.ia_valid = ATTR_MODE | ATTR_CTIME;
0251 attr.ia_mode = mode;
0252 attr.ia_ctime = current_time(inode);
0253 rc = jffs2_do_setattr(inode, &attr);
0254 if (rc < 0)
0255 return rc;
0256 }
0257 }
0258 break;
0259 case ACL_TYPE_DEFAULT:
0260 xprefix = JFFS2_XPREFIX_ACL_DEFAULT;
0261 if (!S_ISDIR(inode->i_mode))
0262 return acl ? -EACCES : 0;
0263 break;
0264 default:
0265 return -EINVAL;
0266 }
0267 rc = __jffs2_set_acl(inode, xprefix, acl);
0268 if (!rc)
0269 set_cached_acl(inode, type, acl);
0270 return rc;
0271 }
0272
0273 int jffs2_init_acl_pre(struct inode *dir_i, struct inode *inode, umode_t *i_mode)
0274 {
0275 struct posix_acl *default_acl, *acl;
0276 int rc;
0277
0278 cache_no_acl(inode);
0279
0280 rc = posix_acl_create(dir_i, i_mode, &default_acl, &acl);
0281 if (rc)
0282 return rc;
0283
0284 if (default_acl) {
0285 set_cached_acl(inode, ACL_TYPE_DEFAULT, default_acl);
0286 posix_acl_release(default_acl);
0287 }
0288 if (acl) {
0289 set_cached_acl(inode, ACL_TYPE_ACCESS, acl);
0290 posix_acl_release(acl);
0291 }
0292 return 0;
0293 }
0294
0295 int jffs2_init_acl_post(struct inode *inode)
0296 {
0297 int rc;
0298
0299 if (inode->i_default_acl) {
0300 rc = __jffs2_set_acl(inode, JFFS2_XPREFIX_ACL_DEFAULT, inode->i_default_acl);
0301 if (rc)
0302 return rc;
0303 }
0304
0305 if (inode->i_acl) {
0306 rc = __jffs2_set_acl(inode, JFFS2_XPREFIX_ACL_ACCESS, inode->i_acl);
0307 if (rc)
0308 return rc;
0309 }
0310
0311 return 0;
0312 }