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


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Copyright (C) 2007 Red Hat.  All rights reserved.
      4 */
      5
      6#include <linux/fs.h>
      7#include <linux/string.h>
      8#include <linux/xattr.h>
      9#include <linux/posix_acl_xattr.h>
     10#include <linux/posix_acl.h>
     11#include <linux/sched.h>
     12#include <linux/sched/mm.h>
     13#include <linux/slab.h>
     14
     15#include "ctree.h"
     16#include "btrfs_inode.h"
     17#include "xattr.h"
     18
     19struct posix_acl *btrfs_get_acl(struct inode *inode, int type, bool rcu)
     20{
     21	int size;
     22	const char *name;
     23	char *value = NULL;
     24	struct posix_acl *acl;
     25
     26	if (rcu)
     27		return ERR_PTR(-ECHILD);
     28
     29	switch (type) {
     30	case ACL_TYPE_ACCESS:
     31		name = XATTR_NAME_POSIX_ACL_ACCESS;
     32		break;
     33	case ACL_TYPE_DEFAULT:
     34		name = XATTR_NAME_POSIX_ACL_DEFAULT;
     35		break;
     36	default:
     37		return ERR_PTR(-EINVAL);
     38	}
     39
     40	size = btrfs_getxattr(inode, name, NULL, 0);
     41	if (size > 0) {
     42		value = kzalloc(size, GFP_KERNEL);
     43		if (!value)
     44			return ERR_PTR(-ENOMEM);
     45		size = btrfs_getxattr(inode, name, value, size);
     46	}
     47	if (size > 0)
     48		acl = posix_acl_from_xattr(&init_user_ns, value, size);
     49	else if (size == -ENODATA || size == 0)
     50		acl = NULL;
     51	else
     52		acl = ERR_PTR(size);
     53	kfree(value);
     54
     55	return acl;
     56}
     57
     58int __btrfs_set_acl(struct btrfs_trans_handle *trans, struct inode *inode,
     59		    struct posix_acl *acl, int type)
     60{
     61	int ret, size = 0;
     62	const char *name;
     63	char *value = NULL;
     64
     65	switch (type) {
     66	case ACL_TYPE_ACCESS:
     67		name = XATTR_NAME_POSIX_ACL_ACCESS;
     68		break;
     69	case ACL_TYPE_DEFAULT:
     70		if (!S_ISDIR(inode->i_mode))
     71			return acl ? -EINVAL : 0;
     72		name = XATTR_NAME_POSIX_ACL_DEFAULT;
     73		break;
     74	default:
     75		return -EINVAL;
     76	}
     77
     78	if (acl) {
     79		unsigned int nofs_flag;
     80
     81		size = posix_acl_xattr_size(acl->a_count);
     82		/*
     83		 * We're holding a transaction handle, so use a NOFS memory
     84		 * allocation context to avoid deadlock if reclaim happens.
     85		 */
     86		nofs_flag = memalloc_nofs_save();
     87		value = kmalloc(size, GFP_KERNEL);
     88		memalloc_nofs_restore(nofs_flag);
     89		if (!value) {
     90			ret = -ENOMEM;
     91			goto out;
     92		}
     93
     94		ret = posix_acl_to_xattr(&init_user_ns, acl, value, size);
     95		if (ret < 0)
     96			goto out;
     97	}
     98
     99	if (trans)
    100		ret = btrfs_setxattr(trans, inode, name, value, size, 0);
    101	else
    102		ret = btrfs_setxattr_trans(inode, name, value, size, 0);
    103
    104out:
    105	kfree(value);
    106
    107	if (!ret)
    108		set_cached_acl(inode, type, acl);
    109
    110	return ret;
    111}
    112
    113int btrfs_set_acl(struct user_namespace *mnt_userns, struct inode *inode,
    114		  struct posix_acl *acl, int type)
    115{
    116	int ret;
    117	umode_t old_mode = inode->i_mode;
    118
    119	if (type == ACL_TYPE_ACCESS && acl) {
    120		ret = posix_acl_update_mode(mnt_userns, inode,
    121					    &inode->i_mode, &acl);
    122		if (ret)
    123			return ret;
    124	}
    125	ret = __btrfs_set_acl(NULL, inode, acl, type);
    126	if (ret)
    127		inode->i_mode = old_mode;
    128	return ret;
    129}