brintos

brintos / linux-shallow public Read only

0
0
Text · 9.8 KiB · 0642649 Raw
412 lines · c
1// SPDX-License-Identifier: GPL-2.02#include <linux/capability.h>3#include <linux/fs.h>4#include <linux/posix_acl.h>5#include "reiserfs.h"6#include <linux/errno.h>7#include <linux/pagemap.h>8#include <linux/xattr.h>9#include <linux/slab.h>10#include <linux/posix_acl_xattr.h>11#include "xattr.h"12#include "acl.h"13#include <linux/uaccess.h>14 15static int __reiserfs_set_acl(struct reiserfs_transaction_handle *th,16			    struct inode *inode, int type,17			    struct posix_acl *acl);18 19 20int21reiserfs_set_acl(struct mnt_idmap *idmap, struct dentry *dentry,22		 struct posix_acl *acl, int type)23{24	int error, error2;25	struct reiserfs_transaction_handle th;26	size_t jcreate_blocks;27	int size = acl ? posix_acl_xattr_size(acl->a_count) : 0;28	int update_mode = 0;29	struct inode *inode = d_inode(dentry);30	umode_t mode = inode->i_mode;31 32	/*33	 * Pessimism: We can't assume that anything from the xattr root up34	 * has been created.35	 */36 37	jcreate_blocks = reiserfs_xattr_jcreate_nblocks(inode) +38			 reiserfs_xattr_nblocks(inode, size) * 2;39 40	reiserfs_write_lock(inode->i_sb);41	error = journal_begin(&th, inode->i_sb, jcreate_blocks);42	reiserfs_write_unlock(inode->i_sb);43	if (error == 0) {44		if (type == ACL_TYPE_ACCESS && acl) {45			error = posix_acl_update_mode(&nop_mnt_idmap, inode,46						      &mode, &acl);47			if (error)48				goto unlock;49			update_mode = 1;50		}51		error = __reiserfs_set_acl(&th, inode, type, acl);52		if (!error && update_mode)53			inode->i_mode = mode;54unlock:55		reiserfs_write_lock(inode->i_sb);56		error2 = journal_end(&th);57		reiserfs_write_unlock(inode->i_sb);58		if (error2)59			error = error2;60	}61 62	return error;63}64 65/*66 * Convert from filesystem to in-memory representation.67 */68static struct posix_acl *reiserfs_posix_acl_from_disk(const void *value, size_t size)69{70	const char *end = (char *)value + size;71	int n, count;72	struct posix_acl *acl;73 74	if (!value)75		return NULL;76	if (size < sizeof(reiserfs_acl_header))77		return ERR_PTR(-EINVAL);78	if (((reiserfs_acl_header *) value)->a_version !=79	    cpu_to_le32(REISERFS_ACL_VERSION))80		return ERR_PTR(-EINVAL);81	value = (char *)value + sizeof(reiserfs_acl_header);82	count = reiserfs_acl_count(size);83	if (count < 0)84		return ERR_PTR(-EINVAL);85	if (count == 0)86		return NULL;87	acl = posix_acl_alloc(count, GFP_NOFS);88	if (!acl)89		return ERR_PTR(-ENOMEM);90	for (n = 0; n < count; n++) {91		reiserfs_acl_entry *entry = (reiserfs_acl_entry *) value;92		if ((char *)value + sizeof(reiserfs_acl_entry_short) > end)93			goto fail;94		acl->a_entries[n].e_tag = le16_to_cpu(entry->e_tag);95		acl->a_entries[n].e_perm = le16_to_cpu(entry->e_perm);96		switch (acl->a_entries[n].e_tag) {97		case ACL_USER_OBJ:98		case ACL_GROUP_OBJ:99		case ACL_MASK:100		case ACL_OTHER:101			value = (char *)value +102			    sizeof(reiserfs_acl_entry_short);103			break;104 105		case ACL_USER:106			value = (char *)value + sizeof(reiserfs_acl_entry);107			if ((char *)value > end)108				goto fail;109			acl->a_entries[n].e_uid = 110				make_kuid(&init_user_ns,111					  le32_to_cpu(entry->e_id));112			break;113		case ACL_GROUP:114			value = (char *)value + sizeof(reiserfs_acl_entry);115			if ((char *)value > end)116				goto fail;117			acl->a_entries[n].e_gid =118				make_kgid(&init_user_ns,119					  le32_to_cpu(entry->e_id));120			break;121 122		default:123			goto fail;124		}125	}126	if (value != end)127		goto fail;128	return acl;129 130fail:131	posix_acl_release(acl);132	return ERR_PTR(-EINVAL);133}134 135/*136 * Convert from in-memory to filesystem representation.137 */138static void *reiserfs_posix_acl_to_disk(const struct posix_acl *acl, size_t * size)139{140	reiserfs_acl_header *ext_acl;141	char *e;142	int n;143 144	*size = reiserfs_acl_size(acl->a_count);145	ext_acl = kmalloc(sizeof(reiserfs_acl_header) +146						  acl->a_count *147						  sizeof(reiserfs_acl_entry),148						  GFP_NOFS);149	if (!ext_acl)150		return ERR_PTR(-ENOMEM);151	ext_acl->a_version = cpu_to_le32(REISERFS_ACL_VERSION);152	e = (char *)ext_acl + sizeof(reiserfs_acl_header);153	for (n = 0; n < acl->a_count; n++) {154		const struct posix_acl_entry *acl_e = &acl->a_entries[n];155		reiserfs_acl_entry *entry = (reiserfs_acl_entry *) e;156		entry->e_tag = cpu_to_le16(acl->a_entries[n].e_tag);157		entry->e_perm = cpu_to_le16(acl->a_entries[n].e_perm);158		switch (acl->a_entries[n].e_tag) {159		case ACL_USER:160			entry->e_id = cpu_to_le32(161				from_kuid(&init_user_ns, acl_e->e_uid));162			e += sizeof(reiserfs_acl_entry);163			break;164		case ACL_GROUP:165			entry->e_id = cpu_to_le32(166				from_kgid(&init_user_ns, acl_e->e_gid));167			e += sizeof(reiserfs_acl_entry);168			break;169 170		case ACL_USER_OBJ:171		case ACL_GROUP_OBJ:172		case ACL_MASK:173		case ACL_OTHER:174			e += sizeof(reiserfs_acl_entry_short);175			break;176 177		default:178			goto fail;179		}180	}181	return (char *)ext_acl;182 183fail:184	kfree(ext_acl);185	return ERR_PTR(-EINVAL);186}187 188/*189 * Inode operation get_posix_acl().190 *191 * inode->i_mutex: down192 * BKL held [before 2.5.x]193 */194struct posix_acl *reiserfs_get_acl(struct inode *inode, int type, bool rcu)195{196	char *name, *value;197	struct posix_acl *acl;198	int size;199	int retval;200 201	if (rcu)202		return ERR_PTR(-ECHILD);203 204	switch (type) {205	case ACL_TYPE_ACCESS:206		name = XATTR_NAME_POSIX_ACL_ACCESS;207		break;208	case ACL_TYPE_DEFAULT:209		name = XATTR_NAME_POSIX_ACL_DEFAULT;210		break;211	default:212		BUG();213	}214 215	size = reiserfs_xattr_get(inode, name, NULL, 0);216	if (size < 0) {217		if (size == -ENODATA || size == -ENOSYS)218			return NULL;219		return ERR_PTR(size);220	}221 222	value = kmalloc(size, GFP_NOFS);223	if (!value)224		return ERR_PTR(-ENOMEM);225 226	retval = reiserfs_xattr_get(inode, name, value, size);227	if (retval == -ENODATA || retval == -ENOSYS) {228		/*229		 * This shouldn't actually happen as it should have230		 * been caught above.. but just in case231		 */232		acl = NULL;233	} else if (retval < 0) {234		acl = ERR_PTR(retval);235	} else {236		acl = reiserfs_posix_acl_from_disk(value, retval);237	}238 239	kfree(value);240	return acl;241}242 243/*244 * Inode operation set_posix_acl().245 *246 * inode->i_mutex: down247 * BKL held [before 2.5.x]248 */249static int250__reiserfs_set_acl(struct reiserfs_transaction_handle *th, struct inode *inode,251		 int type, struct posix_acl *acl)252{253	char *name;254	void *value = NULL;255	size_t size = 0;256	int error;257 258	switch (type) {259	case ACL_TYPE_ACCESS:260		name = XATTR_NAME_POSIX_ACL_ACCESS;261		break;262	case ACL_TYPE_DEFAULT:263		name = XATTR_NAME_POSIX_ACL_DEFAULT;264		if (!S_ISDIR(inode->i_mode))265			return acl ? -EACCES : 0;266		break;267	default:268		return -EINVAL;269	}270 271	if (acl) {272		value = reiserfs_posix_acl_to_disk(acl, &size);273		if (IS_ERR(value))274			return (int)PTR_ERR(value);275	}276 277	error = reiserfs_xattr_set_handle(th, inode, name, value, size, 0);278 279	/*280	 * Ensure that the inode gets dirtied if we're only using281	 * the mode bits and an old ACL didn't exist. We don't need282	 * to check if the inode is hashed here since we won't get283	 * called by reiserfs_inherit_default_acl().284	 */285	if (error == -ENODATA) {286		error = 0;287		if (type == ACL_TYPE_ACCESS) {288			inode_set_ctime_current(inode);289			mark_inode_dirty(inode);290		}291	}292 293	kfree(value);294 295	if (!error)296		set_cached_acl(inode, type, acl);297 298	return error;299}300 301/*302 * dir->i_mutex: locked,303 * inode is new and not released into the wild yet304 */305int306reiserfs_inherit_default_acl(struct reiserfs_transaction_handle *th,307			     struct inode *dir, struct dentry *dentry,308			     struct inode *inode)309{310	struct posix_acl *default_acl, *acl;311	int err = 0;312 313	/* ACLs only get applied to files and directories */314	if (S_ISLNK(inode->i_mode))315		return 0;316 317	/*318	 * ACLs can only be used on "new" objects, so if it's an old object319	 * there is nothing to inherit from320	 */321	if (get_inode_sd_version(dir) == STAT_DATA_V1)322		goto apply_umask;323 324	/*325	 * Don't apply ACLs to objects in the .reiserfs_priv tree.. This326	 * would be useless since permissions are ignored, and a pain because327	 * it introduces locking cycles328	 */329	if (IS_PRIVATE(inode))330		goto apply_umask;331 332	err = posix_acl_create(dir, &inode->i_mode, &default_acl, &acl);333	if (err)334		return err;335 336	if (default_acl) {337		err = __reiserfs_set_acl(th, inode, ACL_TYPE_DEFAULT,338					 default_acl);339		posix_acl_release(default_acl);340	}341	if (acl) {342		if (!err)343			err = __reiserfs_set_acl(th, inode, ACL_TYPE_ACCESS,344						 acl);345		posix_acl_release(acl);346	}347 348	return err;349 350apply_umask:351	/* no ACL, apply umask */352	inode->i_mode &= ~current_umask();353	return err;354}355 356/* This is used to cache the default acl before a new object is created.357 * The biggest reason for this is to get an idea of how many blocks will358 * actually be required for the create operation if we must inherit an ACL.359 * An ACL write can add up to 3 object creations and an additional file write360 * so we'd prefer not to reserve that many blocks in the journal if we can.361 * It also has the advantage of not loading the ACL with a transaction open,362 * this may seem silly, but if the owner of the directory is doing the363 * creation, the ACL may not be loaded since the permissions wouldn't require364 * it.365 * We return the number of blocks required for the transaction.366 */367int reiserfs_cache_default_acl(struct inode *inode)368{369	struct posix_acl *acl;370	int nblocks = 0;371 372	if (IS_PRIVATE(inode))373		return 0;374 375	acl = get_inode_acl(inode, ACL_TYPE_DEFAULT);376 377	if (acl && !IS_ERR(acl)) {378		int size = reiserfs_acl_size(acl->a_count);379 380		/* Other xattrs can be created during inode creation. We don't381		 * want to claim too many blocks, so we check to see if we382		 * need to create the tree to the xattrs, and then we383		 * just want two files. */384		nblocks = reiserfs_xattr_jcreate_nblocks(inode);385		nblocks += JOURNAL_BLOCKS_PER_OBJECT(inode->i_sb);386 387		REISERFS_I(inode)->i_flags |= i_has_xattr_dir;388 389		/* We need to account for writes + bitmaps for two files */390		nblocks += reiserfs_xattr_nblocks(inode, size) * 4;391		posix_acl_release(acl);392	}393 394	return nblocks;395}396 397/*398 * Called under i_mutex399 */400int reiserfs_acl_chmod(struct dentry *dentry)401{402	struct inode *inode = d_inode(dentry);403 404	if (IS_PRIVATE(inode))405		return 0;406	if (get_inode_sd_version(inode) == STAT_DATA_V1 ||407	    !reiserfs_posixacl(inode->i_sb))408		return 0;409 410	return posix_acl_chmod(&nop_mnt_idmap, dentry, inode->i_mode);411}412