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 (5819B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * linux/fs/ceph/acl.c
      4 *
      5 * Copyright (C) 2013 Guangliang Zhao, <lucienchao@gmail.com>
      6 */
      7
      8#include <linux/ceph/ceph_debug.h>
      9#include <linux/fs.h>
     10#include <linux/string.h>
     11#include <linux/xattr.h>
     12#include <linux/posix_acl_xattr.h>
     13#include <linux/posix_acl.h>
     14#include <linux/sched.h>
     15#include <linux/slab.h>
     16
     17#include "super.h"
     18
     19static inline void ceph_set_cached_acl(struct inode *inode,
     20					int type, struct posix_acl *acl)
     21{
     22	struct ceph_inode_info *ci = ceph_inode(inode);
     23
     24	spin_lock(&ci->i_ceph_lock);
     25	if (__ceph_caps_issued_mask_metric(ci, CEPH_CAP_XATTR_SHARED, 0))
     26		set_cached_acl(inode, type, acl);
     27	else
     28		forget_cached_acl(inode, type);
     29	spin_unlock(&ci->i_ceph_lock);
     30}
     31
     32struct posix_acl *ceph_get_acl(struct inode *inode, int type, bool rcu)
     33{
     34	int size;
     35	unsigned int retry_cnt = 0;
     36	const char *name;
     37	char *value = NULL;
     38	struct posix_acl *acl;
     39
     40	if (rcu)
     41		return ERR_PTR(-ECHILD);
     42
     43	switch (type) {
     44	case ACL_TYPE_ACCESS:
     45		name = XATTR_NAME_POSIX_ACL_ACCESS;
     46		break;
     47	case ACL_TYPE_DEFAULT:
     48		name = XATTR_NAME_POSIX_ACL_DEFAULT;
     49		break;
     50	default:
     51		BUG();
     52	}
     53
     54retry:
     55	size = __ceph_getxattr(inode, name, "", 0);
     56	if (size > 0) {
     57		value = kzalloc(size, GFP_NOFS);
     58		if (!value)
     59			return ERR_PTR(-ENOMEM);
     60		size = __ceph_getxattr(inode, name, value, size);
     61	}
     62
     63	if (size == -ERANGE && retry_cnt < 10) {
     64		retry_cnt++;
     65		kfree(value);
     66		value = NULL;
     67		goto retry;
     68	}
     69
     70	if (size > 0) {
     71		acl = posix_acl_from_xattr(&init_user_ns, value, size);
     72	} else if (size == -ENODATA || size == 0) {
     73		acl = NULL;
     74	} else {
     75		pr_err_ratelimited("get acl %llx.%llx failed, err=%d\n",
     76				   ceph_vinop(inode), size);
     77		acl = ERR_PTR(-EIO);
     78	}
     79
     80	kfree(value);
     81
     82	if (!IS_ERR(acl))
     83		ceph_set_cached_acl(inode, type, acl);
     84
     85	return acl;
     86}
     87
     88int ceph_set_acl(struct user_namespace *mnt_userns, struct inode *inode,
     89		 struct posix_acl *acl, int type)
     90{
     91	int ret = 0, size = 0;
     92	const char *name = NULL;
     93	char *value = NULL;
     94	struct iattr newattrs;
     95	struct timespec64 old_ctime = inode->i_ctime;
     96	umode_t new_mode = inode->i_mode, old_mode = inode->i_mode;
     97
     98	if (ceph_snap(inode) != CEPH_NOSNAP) {
     99		ret = -EROFS;
    100		goto out;
    101	}
    102
    103	switch (type) {
    104	case ACL_TYPE_ACCESS:
    105		name = XATTR_NAME_POSIX_ACL_ACCESS;
    106		if (acl) {
    107			ret = posix_acl_update_mode(&init_user_ns, inode,
    108						    &new_mode, &acl);
    109			if (ret)
    110				goto out;
    111		}
    112		break;
    113	case ACL_TYPE_DEFAULT:
    114		if (!S_ISDIR(inode->i_mode)) {
    115			ret = acl ? -EINVAL : 0;
    116			goto out;
    117		}
    118		name = XATTR_NAME_POSIX_ACL_DEFAULT;
    119		break;
    120	default:
    121		ret = -EINVAL;
    122		goto out;
    123	}
    124
    125	if (acl) {
    126		size = posix_acl_xattr_size(acl->a_count);
    127		value = kmalloc(size, GFP_NOFS);
    128		if (!value) {
    129			ret = -ENOMEM;
    130			goto out;
    131		}
    132
    133		ret = posix_acl_to_xattr(&init_user_ns, acl, value, size);
    134		if (ret < 0)
    135			goto out_free;
    136	}
    137
    138	if (new_mode != old_mode) {
    139		newattrs.ia_ctime = current_time(inode);
    140		newattrs.ia_mode = new_mode;
    141		newattrs.ia_valid = ATTR_MODE | ATTR_CTIME;
    142		ret = __ceph_setattr(inode, &newattrs);
    143		if (ret)
    144			goto out_free;
    145	}
    146
    147	ret = __ceph_setxattr(inode, name, value, size, 0);
    148	if (ret) {
    149		if (new_mode != old_mode) {
    150			newattrs.ia_ctime = old_ctime;
    151			newattrs.ia_mode = old_mode;
    152			newattrs.ia_valid = ATTR_MODE | ATTR_CTIME;
    153			__ceph_setattr(inode, &newattrs);
    154		}
    155		goto out_free;
    156	}
    157
    158	ceph_set_cached_acl(inode, type, acl);
    159
    160out_free:
    161	kfree(value);
    162out:
    163	return ret;
    164}
    165
    166int ceph_pre_init_acls(struct inode *dir, umode_t *mode,
    167		       struct ceph_acl_sec_ctx *as_ctx)
    168{
    169	struct posix_acl *acl, *default_acl;
    170	size_t val_size1 = 0, val_size2 = 0;
    171	struct ceph_pagelist *pagelist = NULL;
    172	void *tmp_buf = NULL;
    173	int err;
    174
    175	err = posix_acl_create(dir, mode, &default_acl, &acl);
    176	if (err)
    177		return err;
    178
    179	if (acl) {
    180		err = posix_acl_equiv_mode(acl, mode);
    181		if (err < 0)
    182			goto out_err;
    183		if (err == 0) {
    184			posix_acl_release(acl);
    185			acl = NULL;
    186		}
    187	}
    188
    189	if (!default_acl && !acl)
    190		return 0;
    191
    192	if (acl)
    193		val_size1 = posix_acl_xattr_size(acl->a_count);
    194	if (default_acl)
    195		val_size2 = posix_acl_xattr_size(default_acl->a_count);
    196
    197	err = -ENOMEM;
    198	tmp_buf = kmalloc(max(val_size1, val_size2), GFP_KERNEL);
    199	if (!tmp_buf)
    200		goto out_err;
    201	pagelist = ceph_pagelist_alloc(GFP_KERNEL);
    202	if (!pagelist)
    203		goto out_err;
    204
    205	err = ceph_pagelist_reserve(pagelist, PAGE_SIZE);
    206	if (err)
    207		goto out_err;
    208
    209	ceph_pagelist_encode_32(pagelist, acl && default_acl ? 2 : 1);
    210
    211	if (acl) {
    212		size_t len = strlen(XATTR_NAME_POSIX_ACL_ACCESS);
    213		err = ceph_pagelist_reserve(pagelist, len + val_size1 + 8);
    214		if (err)
    215			goto out_err;
    216		ceph_pagelist_encode_string(pagelist, XATTR_NAME_POSIX_ACL_ACCESS,
    217					    len);
    218		err = posix_acl_to_xattr(&init_user_ns, acl,
    219					 tmp_buf, val_size1);
    220		if (err < 0)
    221			goto out_err;
    222		ceph_pagelist_encode_32(pagelist, val_size1);
    223		ceph_pagelist_append(pagelist, tmp_buf, val_size1);
    224	}
    225	if (default_acl) {
    226		size_t len = strlen(XATTR_NAME_POSIX_ACL_DEFAULT);
    227		err = ceph_pagelist_reserve(pagelist, len + val_size2 + 8);
    228		if (err)
    229			goto out_err;
    230		ceph_pagelist_encode_string(pagelist,
    231					  XATTR_NAME_POSIX_ACL_DEFAULT, len);
    232		err = posix_acl_to_xattr(&init_user_ns, default_acl,
    233					 tmp_buf, val_size2);
    234		if (err < 0)
    235			goto out_err;
    236		ceph_pagelist_encode_32(pagelist, val_size2);
    237		ceph_pagelist_append(pagelist, tmp_buf, val_size2);
    238	}
    239
    240	kfree(tmp_buf);
    241
    242	as_ctx->acl = acl;
    243	as_ctx->default_acl = default_acl;
    244	as_ctx->pagelist = pagelist;
    245	return 0;
    246
    247out_err:
    248	posix_acl_release(acl);
    249	posix_acl_release(default_acl);
    250	kfree(tmp_buf);
    251	if (pagelist)
    252		ceph_pagelist_release(pagelist);
    253	return err;
    254}
    255
    256void ceph_init_inode_acls(struct inode *inode, struct ceph_acl_sec_ctx *as_ctx)
    257{
    258	if (!inode)
    259		return;
    260	ceph_set_cached_acl(inode, ACL_TYPE_ACCESS, as_ctx->acl);
    261	ceph_set_cached_acl(inode, ACL_TYPE_DEFAULT, as_ctx->default_acl);
    262}