Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * JFFS2 -- Journalling Flash File System, Version 2.
0003  *
0004  * Copyright © 2006  NEC Corporation
0005  *
0006  * Created by KaiGai Kohei <kaigai@ak.jp.nec.com>
0007  *
0008  * For licensing information, see the file 'LICENCE' in this directory.
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 }