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

xattr.c (23815B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * linux/fs/hfsplus/xattr.c
      4 *
      5 * Vyacheslav Dubeyko <slava@dubeyko.com>
      6 *
      7 * Logic of processing extended attributes
      8 */
      9
     10#include "hfsplus_fs.h"
     11#include <linux/nls.h>
     12#include "xattr.h"
     13
     14static int hfsplus_removexattr(struct inode *inode, const char *name);
     15
     16const struct xattr_handler *hfsplus_xattr_handlers[] = {
     17	&hfsplus_xattr_osx_handler,
     18	&hfsplus_xattr_user_handler,
     19	&hfsplus_xattr_trusted_handler,
     20	&hfsplus_xattr_security_handler,
     21	NULL
     22};
     23
     24static int strcmp_xattr_finder_info(const char *name)
     25{
     26	if (name) {
     27		return strncmp(name, HFSPLUS_XATTR_FINDER_INFO_NAME,
     28				sizeof(HFSPLUS_XATTR_FINDER_INFO_NAME));
     29	}
     30	return -1;
     31}
     32
     33static int strcmp_xattr_acl(const char *name)
     34{
     35	if (name) {
     36		return strncmp(name, HFSPLUS_XATTR_ACL_NAME,
     37				sizeof(HFSPLUS_XATTR_ACL_NAME));
     38	}
     39	return -1;
     40}
     41
     42static bool is_known_namespace(const char *name)
     43{
     44	if (strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN) &&
     45	    strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN) &&
     46	    strncmp(name, XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN) &&
     47	    strncmp(name, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN))
     48		return false;
     49
     50	return true;
     51}
     52
     53static void hfsplus_init_header_node(struct inode *attr_file,
     54					u32 clump_size,
     55					char *buf, u16 node_size)
     56{
     57	struct hfs_bnode_desc *desc;
     58	struct hfs_btree_header_rec *head;
     59	u16 offset;
     60	__be16 *rec_offsets;
     61	u32 hdr_node_map_rec_bits;
     62	char *bmp;
     63	u32 used_nodes;
     64	u32 used_bmp_bytes;
     65	u64 tmp;
     66
     67	hfs_dbg(ATTR_MOD, "init_hdr_attr_file: clump %u, node_size %u\n",
     68		clump_size, node_size);
     69
     70	/* The end of the node contains list of record offsets */
     71	rec_offsets = (__be16 *)(buf + node_size);
     72
     73	desc = (struct hfs_bnode_desc *)buf;
     74	desc->type = HFS_NODE_HEADER;
     75	desc->num_recs = cpu_to_be16(HFSPLUS_BTREE_HDR_NODE_RECS_COUNT);
     76	offset = sizeof(struct hfs_bnode_desc);
     77	*--rec_offsets = cpu_to_be16(offset);
     78
     79	head = (struct hfs_btree_header_rec *)(buf + offset);
     80	head->node_size = cpu_to_be16(node_size);
     81	tmp = i_size_read(attr_file);
     82	do_div(tmp, node_size);
     83	head->node_count = cpu_to_be32(tmp);
     84	head->free_nodes = cpu_to_be32(be32_to_cpu(head->node_count) - 1);
     85	head->clump_size = cpu_to_be32(clump_size);
     86	head->attributes |= cpu_to_be32(HFS_TREE_BIGKEYS | HFS_TREE_VARIDXKEYS);
     87	head->max_key_len = cpu_to_be16(HFSPLUS_ATTR_KEYLEN - sizeof(u16));
     88	offset += sizeof(struct hfs_btree_header_rec);
     89	*--rec_offsets = cpu_to_be16(offset);
     90	offset += HFSPLUS_BTREE_HDR_USER_BYTES;
     91	*--rec_offsets = cpu_to_be16(offset);
     92
     93	hdr_node_map_rec_bits = 8 * (node_size - offset - (4 * sizeof(u16)));
     94	if (be32_to_cpu(head->node_count) > hdr_node_map_rec_bits) {
     95		u32 map_node_bits;
     96		u32 map_nodes;
     97
     98		desc->next = cpu_to_be32(be32_to_cpu(head->leaf_tail) + 1);
     99		map_node_bits = 8 * (node_size - sizeof(struct hfs_bnode_desc) -
    100					(2 * sizeof(u16)) - 2);
    101		map_nodes = (be32_to_cpu(head->node_count) -
    102				hdr_node_map_rec_bits +
    103				(map_node_bits - 1)) / map_node_bits;
    104		be32_add_cpu(&head->free_nodes, 0 - map_nodes);
    105	}
    106
    107	bmp = buf + offset;
    108	used_nodes =
    109		be32_to_cpu(head->node_count) - be32_to_cpu(head->free_nodes);
    110	used_bmp_bytes = used_nodes / 8;
    111	if (used_bmp_bytes) {
    112		memset(bmp, 0xFF, used_bmp_bytes);
    113		bmp += used_bmp_bytes;
    114		used_nodes %= 8;
    115	}
    116	*bmp = ~(0xFF >> used_nodes);
    117	offset += hdr_node_map_rec_bits / 8;
    118	*--rec_offsets = cpu_to_be16(offset);
    119}
    120
    121static int hfsplus_create_attributes_file(struct super_block *sb)
    122{
    123	int err = 0;
    124	struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb);
    125	struct inode *attr_file;
    126	struct hfsplus_inode_info *hip;
    127	u32 clump_size;
    128	u16 node_size = HFSPLUS_ATTR_TREE_NODE_SIZE;
    129	char *buf;
    130	int index, written;
    131	struct address_space *mapping;
    132	struct page *page;
    133	int old_state = HFSPLUS_EMPTY_ATTR_TREE;
    134
    135	hfs_dbg(ATTR_MOD, "create_attr_file: ino %d\n", HFSPLUS_ATTR_CNID);
    136
    137check_attr_tree_state_again:
    138	switch (atomic_read(&sbi->attr_tree_state)) {
    139	case HFSPLUS_EMPTY_ATTR_TREE:
    140		if (old_state != atomic_cmpxchg(&sbi->attr_tree_state,
    141						old_state,
    142						HFSPLUS_CREATING_ATTR_TREE))
    143			goto check_attr_tree_state_again;
    144		break;
    145	case HFSPLUS_CREATING_ATTR_TREE:
    146		/*
    147		 * This state means that another thread is in process
    148		 * of AttributesFile creation. Theoretically, it is
    149		 * possible to be here. But really __setxattr() method
    150		 * first of all calls hfs_find_init() for lookup in
    151		 * B-tree of CatalogFile. This method locks mutex of
    152		 * CatalogFile's B-tree. As a result, if some thread
    153		 * is inside AttributedFile creation operation then
    154		 * another threads will be waiting unlocking of
    155		 * CatalogFile's B-tree's mutex. However, if code will
    156		 * change then we will return error code (-EAGAIN) from
    157		 * here. Really, it means that first try to set of xattr
    158		 * fails with error but second attempt will have success.
    159		 */
    160		return -EAGAIN;
    161	case HFSPLUS_VALID_ATTR_TREE:
    162		return 0;
    163	case HFSPLUS_FAILED_ATTR_TREE:
    164		return -EOPNOTSUPP;
    165	default:
    166		BUG();
    167	}
    168
    169	attr_file = hfsplus_iget(sb, HFSPLUS_ATTR_CNID);
    170	if (IS_ERR(attr_file)) {
    171		pr_err("failed to load attributes file\n");
    172		return PTR_ERR(attr_file);
    173	}
    174
    175	BUG_ON(i_size_read(attr_file) != 0);
    176
    177	hip = HFSPLUS_I(attr_file);
    178
    179	clump_size = hfsplus_calc_btree_clump_size(sb->s_blocksize,
    180						    node_size,
    181						    sbi->sect_count,
    182						    HFSPLUS_ATTR_CNID);
    183
    184	mutex_lock(&hip->extents_lock);
    185	hip->clump_blocks = clump_size >> sbi->alloc_blksz_shift;
    186	mutex_unlock(&hip->extents_lock);
    187
    188	if (sbi->free_blocks <= (hip->clump_blocks << 1)) {
    189		err = -ENOSPC;
    190		goto end_attr_file_creation;
    191	}
    192
    193	while (hip->alloc_blocks < hip->clump_blocks) {
    194		err = hfsplus_file_extend(attr_file, false);
    195		if (unlikely(err)) {
    196			pr_err("failed to extend attributes file\n");
    197			goto end_attr_file_creation;
    198		}
    199		hip->phys_size = attr_file->i_size =
    200			(loff_t)hip->alloc_blocks << sbi->alloc_blksz_shift;
    201		hip->fs_blocks = hip->alloc_blocks << sbi->fs_shift;
    202		inode_set_bytes(attr_file, attr_file->i_size);
    203	}
    204
    205	buf = kzalloc(node_size, GFP_NOFS);
    206	if (!buf) {
    207		err = -ENOMEM;
    208		goto end_attr_file_creation;
    209	}
    210
    211	hfsplus_init_header_node(attr_file, clump_size, buf, node_size);
    212
    213	mapping = attr_file->i_mapping;
    214
    215	index = 0;
    216	written = 0;
    217	for (; written < node_size; index++, written += PAGE_SIZE) {
    218		void *kaddr;
    219
    220		page = read_mapping_page(mapping, index, NULL);
    221		if (IS_ERR(page)) {
    222			err = PTR_ERR(page);
    223			goto failed_header_node_init;
    224		}
    225
    226		kaddr = kmap_atomic(page);
    227		memcpy(kaddr, buf + written,
    228			min_t(size_t, PAGE_SIZE, node_size - written));
    229		kunmap_atomic(kaddr);
    230
    231		set_page_dirty(page);
    232		put_page(page);
    233	}
    234
    235	hfsplus_mark_inode_dirty(attr_file, HFSPLUS_I_ATTR_DIRTY);
    236
    237	sbi->attr_tree = hfs_btree_open(sb, HFSPLUS_ATTR_CNID);
    238	if (!sbi->attr_tree)
    239		pr_err("failed to load attributes file\n");
    240
    241failed_header_node_init:
    242	kfree(buf);
    243
    244end_attr_file_creation:
    245	iput(attr_file);
    246
    247	if (!err)
    248		atomic_set(&sbi->attr_tree_state, HFSPLUS_VALID_ATTR_TREE);
    249	else if (err == -ENOSPC)
    250		atomic_set(&sbi->attr_tree_state, HFSPLUS_EMPTY_ATTR_TREE);
    251	else
    252		atomic_set(&sbi->attr_tree_state, HFSPLUS_FAILED_ATTR_TREE);
    253
    254	return err;
    255}
    256
    257int __hfsplus_setxattr(struct inode *inode, const char *name,
    258			const void *value, size_t size, int flags)
    259{
    260	int err = 0;
    261	struct hfs_find_data cat_fd;
    262	hfsplus_cat_entry entry;
    263	u16 cat_entry_flags, cat_entry_type;
    264	u16 folder_finderinfo_len = sizeof(struct DInfo) +
    265					sizeof(struct DXInfo);
    266	u16 file_finderinfo_len = sizeof(struct FInfo) +
    267					sizeof(struct FXInfo);
    268
    269	if ((!S_ISREG(inode->i_mode) &&
    270			!S_ISDIR(inode->i_mode)) ||
    271				HFSPLUS_IS_RSRC(inode))
    272		return -EOPNOTSUPP;
    273
    274	if (value == NULL)
    275		return hfsplus_removexattr(inode, name);
    276
    277	err = hfs_find_init(HFSPLUS_SB(inode->i_sb)->cat_tree, &cat_fd);
    278	if (err) {
    279		pr_err("can't init xattr find struct\n");
    280		return err;
    281	}
    282
    283	err = hfsplus_find_cat(inode->i_sb, inode->i_ino, &cat_fd);
    284	if (err) {
    285		pr_err("catalog searching failed\n");
    286		goto end_setxattr;
    287	}
    288
    289	if (!strcmp_xattr_finder_info(name)) {
    290		if (flags & XATTR_CREATE) {
    291			pr_err("xattr exists yet\n");
    292			err = -EOPNOTSUPP;
    293			goto end_setxattr;
    294		}
    295		hfs_bnode_read(cat_fd.bnode, &entry, cat_fd.entryoffset,
    296					sizeof(hfsplus_cat_entry));
    297		if (be16_to_cpu(entry.type) == HFSPLUS_FOLDER) {
    298			if (size == folder_finderinfo_len) {
    299				memcpy(&entry.folder.info, value,
    300						folder_finderinfo_len);
    301				hfs_bnode_write(cat_fd.bnode, &entry,
    302					cat_fd.entryoffset,
    303					sizeof(struct hfsplus_cat_folder));
    304				hfsplus_mark_inode_dirty(inode,
    305						HFSPLUS_I_CAT_DIRTY);
    306			} else {
    307				err = -ERANGE;
    308				goto end_setxattr;
    309			}
    310		} else if (be16_to_cpu(entry.type) == HFSPLUS_FILE) {
    311			if (size == file_finderinfo_len) {
    312				memcpy(&entry.file.info, value,
    313						file_finderinfo_len);
    314				hfs_bnode_write(cat_fd.bnode, &entry,
    315					cat_fd.entryoffset,
    316					sizeof(struct hfsplus_cat_file));
    317				hfsplus_mark_inode_dirty(inode,
    318						HFSPLUS_I_CAT_DIRTY);
    319			} else {
    320				err = -ERANGE;
    321				goto end_setxattr;
    322			}
    323		} else {
    324			err = -EOPNOTSUPP;
    325			goto end_setxattr;
    326		}
    327		goto end_setxattr;
    328	}
    329
    330	if (!HFSPLUS_SB(inode->i_sb)->attr_tree) {
    331		err = hfsplus_create_attributes_file(inode->i_sb);
    332		if (unlikely(err))
    333			goto end_setxattr;
    334	}
    335
    336	if (hfsplus_attr_exists(inode, name)) {
    337		if (flags & XATTR_CREATE) {
    338			pr_err("xattr exists yet\n");
    339			err = -EOPNOTSUPP;
    340			goto end_setxattr;
    341		}
    342		err = hfsplus_delete_attr(inode, name);
    343		if (err)
    344			goto end_setxattr;
    345		err = hfsplus_create_attr(inode, name, value, size);
    346		if (err)
    347			goto end_setxattr;
    348	} else {
    349		if (flags & XATTR_REPLACE) {
    350			pr_err("cannot replace xattr\n");
    351			err = -EOPNOTSUPP;
    352			goto end_setxattr;
    353		}
    354		err = hfsplus_create_attr(inode, name, value, size);
    355		if (err)
    356			goto end_setxattr;
    357	}
    358
    359	cat_entry_type = hfs_bnode_read_u16(cat_fd.bnode, cat_fd.entryoffset);
    360	if (cat_entry_type == HFSPLUS_FOLDER) {
    361		cat_entry_flags = hfs_bnode_read_u16(cat_fd.bnode,
    362				    cat_fd.entryoffset +
    363				    offsetof(struct hfsplus_cat_folder, flags));
    364		cat_entry_flags |= HFSPLUS_XATTR_EXISTS;
    365		if (!strcmp_xattr_acl(name))
    366			cat_entry_flags |= HFSPLUS_ACL_EXISTS;
    367		hfs_bnode_write_u16(cat_fd.bnode, cat_fd.entryoffset +
    368				offsetof(struct hfsplus_cat_folder, flags),
    369				cat_entry_flags);
    370		hfsplus_mark_inode_dirty(inode, HFSPLUS_I_CAT_DIRTY);
    371	} else if (cat_entry_type == HFSPLUS_FILE) {
    372		cat_entry_flags = hfs_bnode_read_u16(cat_fd.bnode,
    373				    cat_fd.entryoffset +
    374				    offsetof(struct hfsplus_cat_file, flags));
    375		cat_entry_flags |= HFSPLUS_XATTR_EXISTS;
    376		if (!strcmp_xattr_acl(name))
    377			cat_entry_flags |= HFSPLUS_ACL_EXISTS;
    378		hfs_bnode_write_u16(cat_fd.bnode, cat_fd.entryoffset +
    379				    offsetof(struct hfsplus_cat_file, flags),
    380				    cat_entry_flags);
    381		hfsplus_mark_inode_dirty(inode, HFSPLUS_I_CAT_DIRTY);
    382	} else {
    383		pr_err("invalid catalog entry type\n");
    384		err = -EIO;
    385		goto end_setxattr;
    386	}
    387
    388end_setxattr:
    389	hfs_find_exit(&cat_fd);
    390	return err;
    391}
    392
    393static int name_len(const char *xattr_name, int xattr_name_len)
    394{
    395	int len = xattr_name_len + 1;
    396
    397	if (!is_known_namespace(xattr_name))
    398		len += XATTR_MAC_OSX_PREFIX_LEN;
    399
    400	return len;
    401}
    402
    403static int copy_name(char *buffer, const char *xattr_name, int name_len)
    404{
    405	int len = name_len;
    406	int offset = 0;
    407
    408	if (!is_known_namespace(xattr_name)) {
    409		memcpy(buffer, XATTR_MAC_OSX_PREFIX, XATTR_MAC_OSX_PREFIX_LEN);
    410		offset += XATTR_MAC_OSX_PREFIX_LEN;
    411		len += XATTR_MAC_OSX_PREFIX_LEN;
    412	}
    413
    414	strncpy(buffer + offset, xattr_name, name_len);
    415	memset(buffer + offset + name_len, 0, 1);
    416	len += 1;
    417
    418	return len;
    419}
    420
    421int hfsplus_setxattr(struct inode *inode, const char *name,
    422		     const void *value, size_t size, int flags,
    423		     const char *prefix, size_t prefixlen)
    424{
    425	char *xattr_name;
    426	int res;
    427
    428	xattr_name = kmalloc(NLS_MAX_CHARSET_SIZE * HFSPLUS_ATTR_MAX_STRLEN + 1,
    429		GFP_KERNEL);
    430	if (!xattr_name)
    431		return -ENOMEM;
    432	strcpy(xattr_name, prefix);
    433	strcpy(xattr_name + prefixlen, name);
    434	res = __hfsplus_setxattr(inode, xattr_name, value, size, flags);
    435	kfree(xattr_name);
    436	return res;
    437}
    438
    439static ssize_t hfsplus_getxattr_finder_info(struct inode *inode,
    440						void *value, size_t size)
    441{
    442	ssize_t res = 0;
    443	struct hfs_find_data fd;
    444	u16 entry_type;
    445	u16 folder_rec_len = sizeof(struct DInfo) + sizeof(struct DXInfo);
    446	u16 file_rec_len = sizeof(struct FInfo) + sizeof(struct FXInfo);
    447	u16 record_len = max(folder_rec_len, file_rec_len);
    448	u8 folder_finder_info[sizeof(struct DInfo) + sizeof(struct DXInfo)];
    449	u8 file_finder_info[sizeof(struct FInfo) + sizeof(struct FXInfo)];
    450
    451	if (size >= record_len) {
    452		res = hfs_find_init(HFSPLUS_SB(inode->i_sb)->cat_tree, &fd);
    453		if (res) {
    454			pr_err("can't init xattr find struct\n");
    455			return res;
    456		}
    457		res = hfsplus_find_cat(inode->i_sb, inode->i_ino, &fd);
    458		if (res)
    459			goto end_getxattr_finder_info;
    460		entry_type = hfs_bnode_read_u16(fd.bnode, fd.entryoffset);
    461
    462		if (entry_type == HFSPLUS_FOLDER) {
    463			hfs_bnode_read(fd.bnode, folder_finder_info,
    464				fd.entryoffset +
    465				offsetof(struct hfsplus_cat_folder, user_info),
    466				folder_rec_len);
    467			memcpy(value, folder_finder_info, folder_rec_len);
    468			res = folder_rec_len;
    469		} else if (entry_type == HFSPLUS_FILE) {
    470			hfs_bnode_read(fd.bnode, file_finder_info,
    471				fd.entryoffset +
    472				offsetof(struct hfsplus_cat_file, user_info),
    473				file_rec_len);
    474			memcpy(value, file_finder_info, file_rec_len);
    475			res = file_rec_len;
    476		} else {
    477			res = -EOPNOTSUPP;
    478			goto end_getxattr_finder_info;
    479		}
    480	} else
    481		res = size ? -ERANGE : record_len;
    482
    483end_getxattr_finder_info:
    484	if (size >= record_len)
    485		hfs_find_exit(&fd);
    486	return res;
    487}
    488
    489ssize_t __hfsplus_getxattr(struct inode *inode, const char *name,
    490			 void *value, size_t size)
    491{
    492	struct hfs_find_data fd;
    493	hfsplus_attr_entry *entry;
    494	__be32 xattr_record_type;
    495	u32 record_type;
    496	u16 record_length = 0;
    497	ssize_t res = 0;
    498
    499	if ((!S_ISREG(inode->i_mode) &&
    500			!S_ISDIR(inode->i_mode)) ||
    501				HFSPLUS_IS_RSRC(inode))
    502		return -EOPNOTSUPP;
    503
    504	if (!strcmp_xattr_finder_info(name))
    505		return hfsplus_getxattr_finder_info(inode, value, size);
    506
    507	if (!HFSPLUS_SB(inode->i_sb)->attr_tree)
    508		return -EOPNOTSUPP;
    509
    510	entry = hfsplus_alloc_attr_entry();
    511	if (!entry) {
    512		pr_err("can't allocate xattr entry\n");
    513		return -ENOMEM;
    514	}
    515
    516	res = hfs_find_init(HFSPLUS_SB(inode->i_sb)->attr_tree, &fd);
    517	if (res) {
    518		pr_err("can't init xattr find struct\n");
    519		goto failed_getxattr_init;
    520	}
    521
    522	res = hfsplus_find_attr(inode->i_sb, inode->i_ino, name, &fd);
    523	if (res) {
    524		if (res == -ENOENT)
    525			res = -ENODATA;
    526		else
    527			pr_err("xattr searching failed\n");
    528		goto out;
    529	}
    530
    531	hfs_bnode_read(fd.bnode, &xattr_record_type,
    532			fd.entryoffset, sizeof(xattr_record_type));
    533	record_type = be32_to_cpu(xattr_record_type);
    534	if (record_type == HFSPLUS_ATTR_INLINE_DATA) {
    535		record_length = hfs_bnode_read_u16(fd.bnode,
    536				fd.entryoffset +
    537				offsetof(struct hfsplus_attr_inline_data,
    538				length));
    539		if (record_length > HFSPLUS_MAX_INLINE_DATA_SIZE) {
    540			pr_err("invalid xattr record size\n");
    541			res = -EIO;
    542			goto out;
    543		}
    544	} else if (record_type == HFSPLUS_ATTR_FORK_DATA ||
    545			record_type == HFSPLUS_ATTR_EXTENTS) {
    546		pr_err("only inline data xattr are supported\n");
    547		res = -EOPNOTSUPP;
    548		goto out;
    549	} else {
    550		pr_err("invalid xattr record\n");
    551		res = -EIO;
    552		goto out;
    553	}
    554
    555	if (size) {
    556		hfs_bnode_read(fd.bnode, entry, fd.entryoffset,
    557				offsetof(struct hfsplus_attr_inline_data,
    558					raw_bytes) + record_length);
    559	}
    560
    561	if (size >= record_length) {
    562		memcpy(value, entry->inline_data.raw_bytes, record_length);
    563		res = record_length;
    564	} else
    565		res = size ? -ERANGE : record_length;
    566
    567out:
    568	hfs_find_exit(&fd);
    569
    570failed_getxattr_init:
    571	hfsplus_destroy_attr_entry(entry);
    572	return res;
    573}
    574
    575ssize_t hfsplus_getxattr(struct inode *inode, const char *name,
    576			 void *value, size_t size,
    577			 const char *prefix, size_t prefixlen)
    578{
    579	int res;
    580	char *xattr_name;
    581
    582	xattr_name = kmalloc(NLS_MAX_CHARSET_SIZE * HFSPLUS_ATTR_MAX_STRLEN + 1,
    583			     GFP_KERNEL);
    584	if (!xattr_name)
    585		return -ENOMEM;
    586
    587	strcpy(xattr_name, prefix);
    588	strcpy(xattr_name + prefixlen, name);
    589
    590	res = __hfsplus_getxattr(inode, xattr_name, value, size);
    591	kfree(xattr_name);
    592	return res;
    593
    594}
    595
    596static inline int can_list(const char *xattr_name)
    597{
    598	if (!xattr_name)
    599		return 0;
    600
    601	return strncmp(xattr_name, XATTR_TRUSTED_PREFIX,
    602			XATTR_TRUSTED_PREFIX_LEN) ||
    603				capable(CAP_SYS_ADMIN);
    604}
    605
    606static ssize_t hfsplus_listxattr_finder_info(struct dentry *dentry,
    607						char *buffer, size_t size)
    608{
    609	ssize_t res = 0;
    610	struct inode *inode = d_inode(dentry);
    611	struct hfs_find_data fd;
    612	u16 entry_type;
    613	u8 folder_finder_info[sizeof(struct DInfo) + sizeof(struct DXInfo)];
    614	u8 file_finder_info[sizeof(struct FInfo) + sizeof(struct FXInfo)];
    615	unsigned long len, found_bit;
    616	int xattr_name_len, symbols_count;
    617
    618	res = hfs_find_init(HFSPLUS_SB(inode->i_sb)->cat_tree, &fd);
    619	if (res) {
    620		pr_err("can't init xattr find struct\n");
    621		return res;
    622	}
    623
    624	res = hfsplus_find_cat(inode->i_sb, inode->i_ino, &fd);
    625	if (res)
    626		goto end_listxattr_finder_info;
    627
    628	entry_type = hfs_bnode_read_u16(fd.bnode, fd.entryoffset);
    629	if (entry_type == HFSPLUS_FOLDER) {
    630		len = sizeof(struct DInfo) + sizeof(struct DXInfo);
    631		hfs_bnode_read(fd.bnode, folder_finder_info,
    632				fd.entryoffset +
    633				offsetof(struct hfsplus_cat_folder, user_info),
    634				len);
    635		found_bit = find_first_bit((void *)folder_finder_info, len*8);
    636	} else if (entry_type == HFSPLUS_FILE) {
    637		len = sizeof(struct FInfo) + sizeof(struct FXInfo);
    638		hfs_bnode_read(fd.bnode, file_finder_info,
    639				fd.entryoffset +
    640				offsetof(struct hfsplus_cat_file, user_info),
    641				len);
    642		found_bit = find_first_bit((void *)file_finder_info, len*8);
    643	} else {
    644		res = -EOPNOTSUPP;
    645		goto end_listxattr_finder_info;
    646	}
    647
    648	if (found_bit >= (len*8))
    649		res = 0;
    650	else {
    651		symbols_count = sizeof(HFSPLUS_XATTR_FINDER_INFO_NAME) - 1;
    652		xattr_name_len =
    653			name_len(HFSPLUS_XATTR_FINDER_INFO_NAME, symbols_count);
    654		if (!buffer || !size) {
    655			if (can_list(HFSPLUS_XATTR_FINDER_INFO_NAME))
    656				res = xattr_name_len;
    657		} else if (can_list(HFSPLUS_XATTR_FINDER_INFO_NAME)) {
    658			if (size < xattr_name_len)
    659				res = -ERANGE;
    660			else {
    661				res = copy_name(buffer,
    662						HFSPLUS_XATTR_FINDER_INFO_NAME,
    663						symbols_count);
    664			}
    665		}
    666	}
    667
    668end_listxattr_finder_info:
    669	hfs_find_exit(&fd);
    670
    671	return res;
    672}
    673
    674ssize_t hfsplus_listxattr(struct dentry *dentry, char *buffer, size_t size)
    675{
    676	ssize_t err;
    677	ssize_t res = 0;
    678	struct inode *inode = d_inode(dentry);
    679	struct hfs_find_data fd;
    680	u16 key_len = 0;
    681	struct hfsplus_attr_key attr_key;
    682	char *strbuf;
    683	int xattr_name_len;
    684
    685	if ((!S_ISREG(inode->i_mode) &&
    686			!S_ISDIR(inode->i_mode)) ||
    687				HFSPLUS_IS_RSRC(inode))
    688		return -EOPNOTSUPP;
    689
    690	res = hfsplus_listxattr_finder_info(dentry, buffer, size);
    691	if (res < 0)
    692		return res;
    693	else if (!HFSPLUS_SB(inode->i_sb)->attr_tree)
    694		return (res == 0) ? -EOPNOTSUPP : res;
    695
    696	err = hfs_find_init(HFSPLUS_SB(inode->i_sb)->attr_tree, &fd);
    697	if (err) {
    698		pr_err("can't init xattr find struct\n");
    699		return err;
    700	}
    701
    702	strbuf = kmalloc(NLS_MAX_CHARSET_SIZE * HFSPLUS_ATTR_MAX_STRLEN +
    703			XATTR_MAC_OSX_PREFIX_LEN + 1, GFP_KERNEL);
    704	if (!strbuf) {
    705		res = -ENOMEM;
    706		goto out;
    707	}
    708
    709	err = hfsplus_find_attr(inode->i_sb, inode->i_ino, NULL, &fd);
    710	if (err) {
    711		if (err == -ENOENT) {
    712			if (res == 0)
    713				res = -ENODATA;
    714			goto end_listxattr;
    715		} else {
    716			res = err;
    717			goto end_listxattr;
    718		}
    719	}
    720
    721	for (;;) {
    722		key_len = hfs_bnode_read_u16(fd.bnode, fd.keyoffset);
    723		if (key_len == 0 || key_len > fd.tree->max_key_len) {
    724			pr_err("invalid xattr key length: %d\n", key_len);
    725			res = -EIO;
    726			goto end_listxattr;
    727		}
    728
    729		hfs_bnode_read(fd.bnode, &attr_key,
    730				fd.keyoffset, key_len + sizeof(key_len));
    731
    732		if (be32_to_cpu(attr_key.cnid) != inode->i_ino)
    733			goto end_listxattr;
    734
    735		xattr_name_len = NLS_MAX_CHARSET_SIZE * HFSPLUS_ATTR_MAX_STRLEN;
    736		if (hfsplus_uni2asc(inode->i_sb,
    737			(const struct hfsplus_unistr *)&fd.key->attr.key_name,
    738					strbuf, &xattr_name_len)) {
    739			pr_err("unicode conversion failed\n");
    740			res = -EIO;
    741			goto end_listxattr;
    742		}
    743
    744		if (!buffer || !size) {
    745			if (can_list(strbuf))
    746				res += name_len(strbuf, xattr_name_len);
    747		} else if (can_list(strbuf)) {
    748			if (size < (res + name_len(strbuf, xattr_name_len))) {
    749				res = -ERANGE;
    750				goto end_listxattr;
    751			} else
    752				res += copy_name(buffer + res,
    753						strbuf, xattr_name_len);
    754		}
    755
    756		if (hfs_brec_goto(&fd, 1))
    757			goto end_listxattr;
    758	}
    759
    760end_listxattr:
    761	kfree(strbuf);
    762out:
    763	hfs_find_exit(&fd);
    764	return res;
    765}
    766
    767static int hfsplus_removexattr(struct inode *inode, const char *name)
    768{
    769	int err = 0;
    770	struct hfs_find_data cat_fd;
    771	u16 flags;
    772	u16 cat_entry_type;
    773	int is_xattr_acl_deleted = 0;
    774	int is_all_xattrs_deleted = 0;
    775
    776	if (!HFSPLUS_SB(inode->i_sb)->attr_tree)
    777		return -EOPNOTSUPP;
    778
    779	if (!strcmp_xattr_finder_info(name))
    780		return -EOPNOTSUPP;
    781
    782	err = hfs_find_init(HFSPLUS_SB(inode->i_sb)->cat_tree, &cat_fd);
    783	if (err) {
    784		pr_err("can't init xattr find struct\n");
    785		return err;
    786	}
    787
    788	err = hfsplus_find_cat(inode->i_sb, inode->i_ino, &cat_fd);
    789	if (err) {
    790		pr_err("catalog searching failed\n");
    791		goto end_removexattr;
    792	}
    793
    794	err = hfsplus_delete_attr(inode, name);
    795	if (err)
    796		goto end_removexattr;
    797
    798	is_xattr_acl_deleted = !strcmp_xattr_acl(name);
    799	is_all_xattrs_deleted = !hfsplus_attr_exists(inode, NULL);
    800
    801	if (!is_xattr_acl_deleted && !is_all_xattrs_deleted)
    802		goto end_removexattr;
    803
    804	cat_entry_type = hfs_bnode_read_u16(cat_fd.bnode, cat_fd.entryoffset);
    805
    806	if (cat_entry_type == HFSPLUS_FOLDER) {
    807		flags = hfs_bnode_read_u16(cat_fd.bnode, cat_fd.entryoffset +
    808				offsetof(struct hfsplus_cat_folder, flags));
    809		if (is_xattr_acl_deleted)
    810			flags &= ~HFSPLUS_ACL_EXISTS;
    811		if (is_all_xattrs_deleted)
    812			flags &= ~HFSPLUS_XATTR_EXISTS;
    813		hfs_bnode_write_u16(cat_fd.bnode, cat_fd.entryoffset +
    814				offsetof(struct hfsplus_cat_folder, flags),
    815				flags);
    816		hfsplus_mark_inode_dirty(inode, HFSPLUS_I_CAT_DIRTY);
    817	} else if (cat_entry_type == HFSPLUS_FILE) {
    818		flags = hfs_bnode_read_u16(cat_fd.bnode, cat_fd.entryoffset +
    819				offsetof(struct hfsplus_cat_file, flags));
    820		if (is_xattr_acl_deleted)
    821			flags &= ~HFSPLUS_ACL_EXISTS;
    822		if (is_all_xattrs_deleted)
    823			flags &= ~HFSPLUS_XATTR_EXISTS;
    824		hfs_bnode_write_u16(cat_fd.bnode, cat_fd.entryoffset +
    825				offsetof(struct hfsplus_cat_file, flags),
    826				flags);
    827		hfsplus_mark_inode_dirty(inode, HFSPLUS_I_CAT_DIRTY);
    828	} else {
    829		pr_err("invalid catalog entry type\n");
    830		err = -EIO;
    831		goto end_removexattr;
    832	}
    833
    834end_removexattr:
    835	hfs_find_exit(&cat_fd);
    836	return err;
    837}
    838
    839static int hfsplus_osx_getxattr(const struct xattr_handler *handler,
    840				struct dentry *unused, struct inode *inode,
    841				const char *name, void *buffer, size_t size)
    842{
    843	/*
    844	 * Don't allow retrieving properly prefixed attributes
    845	 * by prepending them with "osx."
    846	 */
    847	if (is_known_namespace(name))
    848		return -EOPNOTSUPP;
    849
    850	/*
    851	 * osx is the namespace we use to indicate an unprefixed
    852	 * attribute on the filesystem (like the ones that OS X
    853	 * creates), so we pass the name through unmodified (after
    854	 * ensuring it doesn't conflict with another namespace).
    855	 */
    856	return __hfsplus_getxattr(inode, name, buffer, size);
    857}
    858
    859static int hfsplus_osx_setxattr(const struct xattr_handler *handler,
    860				struct user_namespace *mnt_userns,
    861				struct dentry *unused, struct inode *inode,
    862				const char *name, const void *buffer,
    863				size_t size, int flags)
    864{
    865	/*
    866	 * Don't allow setting properly prefixed attributes
    867	 * by prepending them with "osx."
    868	 */
    869	if (is_known_namespace(name))
    870		return -EOPNOTSUPP;
    871
    872	/*
    873	 * osx is the namespace we use to indicate an unprefixed
    874	 * attribute on the filesystem (like the ones that OS X
    875	 * creates), so we pass the name through unmodified (after
    876	 * ensuring it doesn't conflict with another namespace).
    877	 */
    878	return __hfsplus_setxattr(inode, name, buffer, size, flags);
    879}
    880
    881const struct xattr_handler hfsplus_xattr_osx_handler = {
    882	.prefix	= XATTR_MAC_OSX_PREFIX,
    883	.get	= hfsplus_osx_getxattr,
    884	.set	= hfsplus_osx_setxattr,
    885};