forked from mirrors/linux
		
	This makes it harder for accidental or malicious changes to hfs_xattr_handlers at runtime. Signed-off-by: Wedson Almeida Filho <walmeida@microsoft.com> Link: https://lore.kernel.org/r/20230930050033.41174-14-wedsonaf@gmail.com Signed-off-by: Christian Brauner <brauner@kernel.org>
		
			
				
	
	
		
			153 lines
		
	
	
	
		
			3.1 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			153 lines
		
	
	
	
		
			3.1 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
// SPDX-License-Identifier: GPL-2.0
 | 
						|
/*
 | 
						|
 *  linux/fs/hfs/attr.c
 | 
						|
 *
 | 
						|
 * (C) 2003 Ardis Technologies <roman@ardistech.com>
 | 
						|
 *
 | 
						|
 * Export hfs data via xattr
 | 
						|
 */
 | 
						|
 | 
						|
 | 
						|
#include <linux/fs.h>
 | 
						|
#include <linux/xattr.h>
 | 
						|
 | 
						|
#include "hfs_fs.h"
 | 
						|
#include "btree.h"
 | 
						|
 | 
						|
enum hfs_xattr_type {
 | 
						|
	HFS_TYPE,
 | 
						|
	HFS_CREATOR,
 | 
						|
};
 | 
						|
 | 
						|
static int __hfs_setxattr(struct inode *inode, enum hfs_xattr_type type,
 | 
						|
			  const void *value, size_t size, int flags)
 | 
						|
{
 | 
						|
	struct hfs_find_data fd;
 | 
						|
	hfs_cat_rec rec;
 | 
						|
	struct hfs_cat_file *file;
 | 
						|
	int res;
 | 
						|
 | 
						|
	if (!S_ISREG(inode->i_mode) || HFS_IS_RSRC(inode))
 | 
						|
		return -EOPNOTSUPP;
 | 
						|
 | 
						|
	res = hfs_find_init(HFS_SB(inode->i_sb)->cat_tree, &fd);
 | 
						|
	if (res)
 | 
						|
		return res;
 | 
						|
	fd.search_key->cat = HFS_I(inode)->cat_key;
 | 
						|
	res = hfs_brec_find(&fd);
 | 
						|
	if (res)
 | 
						|
		goto out;
 | 
						|
	hfs_bnode_read(fd.bnode, &rec, fd.entryoffset,
 | 
						|
			sizeof(struct hfs_cat_file));
 | 
						|
	file = &rec.file;
 | 
						|
 | 
						|
	switch (type) {
 | 
						|
	case HFS_TYPE:
 | 
						|
		if (size == 4)
 | 
						|
			memcpy(&file->UsrWds.fdType, value, 4);
 | 
						|
		else
 | 
						|
			res = -ERANGE;
 | 
						|
		break;
 | 
						|
 | 
						|
	case HFS_CREATOR:
 | 
						|
		if (size == 4)
 | 
						|
			memcpy(&file->UsrWds.fdCreator, value, 4);
 | 
						|
		else
 | 
						|
			res = -ERANGE;
 | 
						|
		break;
 | 
						|
	}
 | 
						|
 | 
						|
	if (!res)
 | 
						|
		hfs_bnode_write(fd.bnode, &rec, fd.entryoffset,
 | 
						|
				sizeof(struct hfs_cat_file));
 | 
						|
out:
 | 
						|
	hfs_find_exit(&fd);
 | 
						|
	return res;
 | 
						|
}
 | 
						|
 | 
						|
static ssize_t __hfs_getxattr(struct inode *inode, enum hfs_xattr_type type,
 | 
						|
			      void *value, size_t size)
 | 
						|
{
 | 
						|
	struct hfs_find_data fd;
 | 
						|
	hfs_cat_rec rec;
 | 
						|
	struct hfs_cat_file *file;
 | 
						|
	ssize_t res = 0;
 | 
						|
 | 
						|
	if (!S_ISREG(inode->i_mode) || HFS_IS_RSRC(inode))
 | 
						|
		return -EOPNOTSUPP;
 | 
						|
 | 
						|
	if (size) {
 | 
						|
		res = hfs_find_init(HFS_SB(inode->i_sb)->cat_tree, &fd);
 | 
						|
		if (res)
 | 
						|
			return res;
 | 
						|
		fd.search_key->cat = HFS_I(inode)->cat_key;
 | 
						|
		res = hfs_brec_find(&fd);
 | 
						|
		if (res)
 | 
						|
			goto out;
 | 
						|
		hfs_bnode_read(fd.bnode, &rec, fd.entryoffset,
 | 
						|
				sizeof(struct hfs_cat_file));
 | 
						|
	}
 | 
						|
	file = &rec.file;
 | 
						|
 | 
						|
	switch (type) {
 | 
						|
	case HFS_TYPE:
 | 
						|
		if (size >= 4) {
 | 
						|
			memcpy(value, &file->UsrWds.fdType, 4);
 | 
						|
			res = 4;
 | 
						|
		} else
 | 
						|
			res = size ? -ERANGE : 4;
 | 
						|
		break;
 | 
						|
 | 
						|
	case HFS_CREATOR:
 | 
						|
		if (size >= 4) {
 | 
						|
			memcpy(value, &file->UsrWds.fdCreator, 4);
 | 
						|
			res = 4;
 | 
						|
		} else
 | 
						|
			res = size ? -ERANGE : 4;
 | 
						|
		break;
 | 
						|
	}
 | 
						|
 | 
						|
out:
 | 
						|
	if (size)
 | 
						|
		hfs_find_exit(&fd);
 | 
						|
	return res;
 | 
						|
}
 | 
						|
 | 
						|
static int hfs_xattr_get(const struct xattr_handler *handler,
 | 
						|
			 struct dentry *unused, struct inode *inode,
 | 
						|
			 const char *name, void *value, size_t size)
 | 
						|
{
 | 
						|
	return __hfs_getxattr(inode, handler->flags, value, size);
 | 
						|
}
 | 
						|
 | 
						|
static int hfs_xattr_set(const struct xattr_handler *handler,
 | 
						|
			 struct mnt_idmap *idmap,
 | 
						|
			 struct dentry *unused, struct inode *inode,
 | 
						|
			 const char *name, const void *value, size_t size,
 | 
						|
			 int flags)
 | 
						|
{
 | 
						|
	if (!value)
 | 
						|
		return -EOPNOTSUPP;
 | 
						|
 | 
						|
	return __hfs_setxattr(inode, handler->flags, value, size, flags);
 | 
						|
}
 | 
						|
 | 
						|
static const struct xattr_handler hfs_creator_handler = {
 | 
						|
	.name = "hfs.creator",
 | 
						|
	.flags = HFS_CREATOR,
 | 
						|
	.get = hfs_xattr_get,
 | 
						|
	.set = hfs_xattr_set,
 | 
						|
};
 | 
						|
 | 
						|
static const struct xattr_handler hfs_type_handler = {
 | 
						|
	.name = "hfs.type",
 | 
						|
	.flags = HFS_TYPE,
 | 
						|
	.get = hfs_xattr_get,
 | 
						|
	.set = hfs_xattr_set,
 | 
						|
};
 | 
						|
 | 
						|
const struct xattr_handler * const hfs_xattr_handlers[] = {
 | 
						|
	&hfs_creator_handler,
 | 
						|
	&hfs_type_handler,
 | 
						|
	NULL
 | 
						|
};
 |