cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

acl.c (6944B)


      1/*
      2 * JFFS2 -- Journalling Flash File System, Version 2.
      3 *
      4 * Copyright © 2006  NEC Corporation
      5 *
      6 * Created by KaiGai Kohei <kaigai@ak.jp.nec.com>
      7 *
      8 * For licensing information, see the file 'LICENCE' in this directory.
      9 *
     10 */
     11
     12#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
     13
     14#include <linux/kernel.h>
     15#include <linux/slab.h>
     16#include <linux/fs.h>
     17#include <linux/sched.h>
     18#include <linux/time.h>
     19#include <linux/crc32.h>
     20#include <linux/jffs2.h>
     21#include <linux/xattr.h>
     22#include <linux/posix_acl_xattr.h>
     23#include <linux/mtd/mtd.h>
     24#include "nodelist.h"
     25
     26static size_t jffs2_acl_size(int count)
     27{
     28	if (count <= 4) {
     29		return sizeof(struct jffs2_acl_header)
     30		       + count * sizeof(struct jffs2_acl_entry_short);
     31	} else {
     32		return sizeof(struct jffs2_acl_header)
     33		       + 4 * sizeof(struct jffs2_acl_entry_short)
     34		       + (count - 4) * sizeof(struct jffs2_acl_entry);
     35	}
     36}
     37
     38static int jffs2_acl_count(size_t size)
     39{
     40	size_t s;
     41
     42	size -= sizeof(struct jffs2_acl_header);
     43	if (size < 4 * sizeof(struct jffs2_acl_entry_short)) {
     44		if (size % sizeof(struct jffs2_acl_entry_short))
     45			return -1;
     46		return size / sizeof(struct jffs2_acl_entry_short);
     47	} else {
     48		s = size - 4 * sizeof(struct jffs2_acl_entry_short);
     49		if (s % sizeof(struct jffs2_acl_entry))
     50			return -1;
     51		return s / sizeof(struct jffs2_acl_entry) + 4;
     52	}
     53}
     54
     55static struct posix_acl *jffs2_acl_from_medium(void *value, size_t size)
     56{
     57	void *end = value + size;
     58	struct jffs2_acl_header *header = value;
     59	struct jffs2_acl_entry *entry;
     60	struct posix_acl *acl;
     61	uint32_t ver;
     62	int i, count;
     63
     64	if (!value)
     65		return NULL;
     66	if (size < sizeof(struct jffs2_acl_header))
     67		return ERR_PTR(-EINVAL);
     68	ver = je32_to_cpu(header->a_version);
     69	if (ver != JFFS2_ACL_VERSION) {
     70		JFFS2_WARNING("Invalid ACL version. (=%u)\n", ver);
     71		return ERR_PTR(-EINVAL);
     72	}
     73
     74	value += sizeof(struct jffs2_acl_header);
     75	count = jffs2_acl_count(size);
     76	if (count < 0)
     77		return ERR_PTR(-EINVAL);
     78	if (count == 0)
     79		return NULL;
     80
     81	acl = posix_acl_alloc(count, GFP_KERNEL);
     82	if (!acl)
     83		return ERR_PTR(-ENOMEM);
     84
     85	for (i=0; i < count; i++) {
     86		entry = value;
     87		if (value + sizeof(struct jffs2_acl_entry_short) > end)
     88			goto fail;
     89		acl->a_entries[i].e_tag = je16_to_cpu(entry->e_tag);
     90		acl->a_entries[i].e_perm = je16_to_cpu(entry->e_perm);
     91		switch (acl->a_entries[i].e_tag) {
     92			case ACL_USER_OBJ:
     93			case ACL_GROUP_OBJ:
     94			case ACL_MASK:
     95			case ACL_OTHER:
     96				value += sizeof(struct jffs2_acl_entry_short);
     97				break;
     98
     99			case ACL_USER:
    100				value += sizeof(struct jffs2_acl_entry);
    101				if (value > end)
    102					goto fail;
    103				acl->a_entries[i].e_uid =
    104					make_kuid(&init_user_ns,
    105						  je32_to_cpu(entry->e_id));
    106				break;
    107			case ACL_GROUP:
    108				value += sizeof(struct jffs2_acl_entry);
    109				if (value > end)
    110					goto fail;
    111				acl->a_entries[i].e_gid =
    112					make_kgid(&init_user_ns,
    113						  je32_to_cpu(entry->e_id));
    114				break;
    115
    116			default:
    117				goto fail;
    118		}
    119	}
    120	if (value != end)
    121		goto fail;
    122	return acl;
    123 fail:
    124	posix_acl_release(acl);
    125	return ERR_PTR(-EINVAL);
    126}
    127
    128static void *jffs2_acl_to_medium(const struct posix_acl *acl, size_t *size)
    129{
    130	struct jffs2_acl_header *header;
    131	struct jffs2_acl_entry *entry;
    132	void *e;
    133	size_t i;
    134
    135	*size = jffs2_acl_size(acl->a_count);
    136	header = kmalloc(struct_size(header, a_entries, acl->a_count),
    137			GFP_KERNEL);
    138	if (!header)
    139		return ERR_PTR(-ENOMEM);
    140	header->a_version = cpu_to_je32(JFFS2_ACL_VERSION);
    141	e = header + 1;
    142	for (i=0; i < acl->a_count; i++) {
    143		const struct posix_acl_entry *acl_e = &acl->a_entries[i];
    144		entry = e;
    145		entry->e_tag = cpu_to_je16(acl_e->e_tag);
    146		entry->e_perm = cpu_to_je16(acl_e->e_perm);
    147		switch(acl_e->e_tag) {
    148			case ACL_USER:
    149				entry->e_id = cpu_to_je32(
    150					from_kuid(&init_user_ns, acl_e->e_uid));
    151				e += sizeof(struct jffs2_acl_entry);
    152				break;
    153			case ACL_GROUP:
    154				entry->e_id = cpu_to_je32(
    155					from_kgid(&init_user_ns, acl_e->e_gid));
    156				e += sizeof(struct jffs2_acl_entry);
    157				break;
    158
    159			case ACL_USER_OBJ:
    160			case ACL_GROUP_OBJ:
    161			case ACL_MASK:
    162			case ACL_OTHER:
    163				e += sizeof(struct jffs2_acl_entry_short);
    164				break;
    165
    166			default:
    167				goto fail;
    168		}
    169	}
    170	return header;
    171 fail:
    172	kfree(header);
    173	return ERR_PTR(-EINVAL);
    174}
    175
    176struct posix_acl *jffs2_get_acl(struct inode *inode, int type, bool rcu)
    177{
    178	struct posix_acl *acl;
    179	char *value = NULL;
    180	int rc, xprefix;
    181
    182	if (rcu)
    183		return ERR_PTR(-ECHILD);
    184
    185	switch (type) {
    186	case ACL_TYPE_ACCESS:
    187		xprefix = JFFS2_XPREFIX_ACL_ACCESS;
    188		break;
    189	case ACL_TYPE_DEFAULT:
    190		xprefix = JFFS2_XPREFIX_ACL_DEFAULT;
    191		break;
    192	default:
    193		BUG();
    194	}
    195	rc = do_jffs2_getxattr(inode, xprefix, "", NULL, 0);
    196	if (rc > 0) {
    197		value = kmalloc(rc, GFP_KERNEL);
    198		if (!value)
    199			return ERR_PTR(-ENOMEM);
    200		rc = do_jffs2_getxattr(inode, xprefix, "", value, rc);
    201	}
    202	if (rc > 0) {
    203		acl = jffs2_acl_from_medium(value, rc);
    204	} else if (rc == -ENODATA || rc == -ENOSYS) {
    205		acl = NULL;
    206	} else {
    207		acl = ERR_PTR(rc);
    208	}
    209	kfree(value);
    210	return acl;
    211}
    212
    213static int __jffs2_set_acl(struct inode *inode, int xprefix, struct posix_acl *acl)
    214{
    215	char *value = NULL;
    216	size_t size = 0;
    217	int rc;
    218
    219	if (acl) {
    220		value = jffs2_acl_to_medium(acl, &size);
    221		if (IS_ERR(value))
    222			return PTR_ERR(value);
    223	}
    224	rc = do_jffs2_setxattr(inode, xprefix, "", value, size, 0);
    225	if (!value && rc == -ENODATA)
    226		rc = 0;
    227	kfree(value);
    228
    229	return rc;
    230}
    231
    232int jffs2_set_acl(struct user_namespace *mnt_userns, struct inode *inode,
    233		  struct posix_acl *acl, int type)
    234{
    235	int rc, xprefix;
    236
    237	switch (type) {
    238	case ACL_TYPE_ACCESS:
    239		xprefix = JFFS2_XPREFIX_ACL_ACCESS;
    240		if (acl) {
    241			umode_t mode;
    242
    243			rc = posix_acl_update_mode(&init_user_ns, inode, &mode,
    244						   &acl);
    245			if (rc)
    246				return rc;
    247			if (inode->i_mode != mode) {
    248				struct iattr attr;
    249
    250				attr.ia_valid = ATTR_MODE | ATTR_CTIME;
    251				attr.ia_mode = mode;
    252				attr.ia_ctime = current_time(inode);
    253				rc = jffs2_do_setattr(inode, &attr);
    254				if (rc < 0)
    255					return rc;
    256			}
    257		}
    258		break;
    259	case ACL_TYPE_DEFAULT:
    260		xprefix = JFFS2_XPREFIX_ACL_DEFAULT;
    261		if (!S_ISDIR(inode->i_mode))
    262			return acl ? -EACCES : 0;
    263		break;
    264	default:
    265		return -EINVAL;
    266	}
    267	rc = __jffs2_set_acl(inode, xprefix, acl);
    268	if (!rc)
    269		set_cached_acl(inode, type, acl);
    270	return rc;
    271}
    272
    273int jffs2_init_acl_pre(struct inode *dir_i, struct inode *inode, umode_t *i_mode)
    274{
    275	struct posix_acl *default_acl, *acl;
    276	int rc;
    277
    278	cache_no_acl(inode);
    279
    280	rc = posix_acl_create(dir_i, i_mode, &default_acl, &acl);
    281	if (rc)
    282		return rc;
    283
    284	if (default_acl) {
    285		set_cached_acl(inode, ACL_TYPE_DEFAULT, default_acl);
    286		posix_acl_release(default_acl);
    287	}
    288	if (acl) {
    289		set_cached_acl(inode, ACL_TYPE_ACCESS, acl);
    290		posix_acl_release(acl);
    291	}
    292	return 0;
    293}
    294
    295int jffs2_init_acl_post(struct inode *inode)
    296{
    297	int rc;
    298
    299	if (inode->i_default_acl) {
    300		rc = __jffs2_set_acl(inode, JFFS2_XPREFIX_ACL_DEFAULT, inode->i_default_acl);
    301		if (rc)
    302			return rc;
    303	}
    304
    305	if (inode->i_acl) {
    306		rc = __jffs2_set_acl(inode, JFFS2_XPREFIX_ACL_ACCESS, inode->i_acl);
    307		if (rc)
    308			return rc;
    309	}
    310
    311	return 0;
    312}