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

xfs_attr_list.c (13580B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Copyright (c) 2000-2005 Silicon Graphics, Inc.
      4 * Copyright (c) 2013 Red Hat, Inc.
      5 * All Rights Reserved.
      6 */
      7#include "xfs.h"
      8#include "xfs_fs.h"
      9#include "xfs_shared.h"
     10#include "xfs_format.h"
     11#include "xfs_log_format.h"
     12#include "xfs_trans_resv.h"
     13#include "xfs_mount.h"
     14#include "xfs_da_format.h"
     15#include "xfs_inode.h"
     16#include "xfs_trans.h"
     17#include "xfs_bmap.h"
     18#include "xfs_da_btree.h"
     19#include "xfs_attr.h"
     20#include "xfs_attr_sf.h"
     21#include "xfs_attr_leaf.h"
     22#include "xfs_error.h"
     23#include "xfs_trace.h"
     24#include "xfs_dir2.h"
     25
     26STATIC int
     27xfs_attr_shortform_compare(const void *a, const void *b)
     28{
     29	xfs_attr_sf_sort_t *sa, *sb;
     30
     31	sa = (xfs_attr_sf_sort_t *)a;
     32	sb = (xfs_attr_sf_sort_t *)b;
     33	if (sa->hash < sb->hash) {
     34		return -1;
     35	} else if (sa->hash > sb->hash) {
     36		return 1;
     37	} else {
     38		return sa->entno - sb->entno;
     39	}
     40}
     41
     42#define XFS_ISRESET_CURSOR(cursor) \
     43	(!((cursor)->initted) && !((cursor)->hashval) && \
     44	 !((cursor)->blkno) && !((cursor)->offset))
     45/*
     46 * Copy out entries of shortform attribute lists for attr_list().
     47 * Shortform attribute lists are not stored in hashval sorted order.
     48 * If the output buffer is not large enough to hold them all, then
     49 * we have to calculate each entries' hashvalue and sort them before
     50 * we can begin returning them to the user.
     51 */
     52static int
     53xfs_attr_shortform_list(
     54	struct xfs_attr_list_context	*context)
     55{
     56	struct xfs_attrlist_cursor_kern	*cursor = &context->cursor;
     57	struct xfs_inode		*dp = context->dp;
     58	struct xfs_attr_sf_sort		*sbuf, *sbp;
     59	struct xfs_attr_shortform	*sf;
     60	struct xfs_attr_sf_entry	*sfe;
     61	int				sbsize, nsbuf, count, i;
     62	int				error = 0;
     63
     64	ASSERT(dp->i_afp != NULL);
     65	sf = (struct xfs_attr_shortform *)dp->i_afp->if_u1.if_data;
     66	ASSERT(sf != NULL);
     67	if (!sf->hdr.count)
     68		return 0;
     69
     70	trace_xfs_attr_list_sf(context);
     71
     72	/*
     73	 * If the buffer is large enough and the cursor is at the start,
     74	 * do not bother with sorting since we will return everything in
     75	 * one buffer and another call using the cursor won't need to be
     76	 * made.
     77	 * Note the generous fudge factor of 16 overhead bytes per entry.
     78	 * If bufsize is zero then put_listent must be a search function
     79	 * and can just scan through what we have.
     80	 */
     81	if (context->bufsize == 0 ||
     82	    (XFS_ISRESET_CURSOR(cursor) &&
     83	     (dp->i_afp->if_bytes + sf->hdr.count * 16) < context->bufsize)) {
     84		for (i = 0, sfe = &sf->list[0]; i < sf->hdr.count; i++) {
     85			if (XFS_IS_CORRUPT(context->dp->i_mount,
     86					   !xfs_attr_namecheck(sfe->nameval,
     87							       sfe->namelen)))
     88				return -EFSCORRUPTED;
     89			context->put_listent(context,
     90					     sfe->flags,
     91					     sfe->nameval,
     92					     (int)sfe->namelen,
     93					     (int)sfe->valuelen);
     94			/*
     95			 * Either search callback finished early or
     96			 * didn't fit it all in the buffer after all.
     97			 */
     98			if (context->seen_enough)
     99				break;
    100			sfe = xfs_attr_sf_nextentry(sfe);
    101		}
    102		trace_xfs_attr_list_sf_all(context);
    103		return 0;
    104	}
    105
    106	/* do no more for a search callback */
    107	if (context->bufsize == 0)
    108		return 0;
    109
    110	/*
    111	 * It didn't all fit, so we have to sort everything on hashval.
    112	 */
    113	sbsize = sf->hdr.count * sizeof(*sbuf);
    114	sbp = sbuf = kmem_alloc(sbsize, KM_NOFS);
    115
    116	/*
    117	 * Scan the attribute list for the rest of the entries, storing
    118	 * the relevant info from only those that match into a buffer.
    119	 */
    120	nsbuf = 0;
    121	for (i = 0, sfe = &sf->list[0]; i < sf->hdr.count; i++) {
    122		if (unlikely(
    123		    ((char *)sfe < (char *)sf) ||
    124		    ((char *)sfe >= ((char *)sf + dp->i_afp->if_bytes)))) {
    125			XFS_CORRUPTION_ERROR("xfs_attr_shortform_list",
    126					     XFS_ERRLEVEL_LOW,
    127					     context->dp->i_mount, sfe,
    128					     sizeof(*sfe));
    129			kmem_free(sbuf);
    130			return -EFSCORRUPTED;
    131		}
    132
    133		sbp->entno = i;
    134		sbp->hash = xfs_da_hashname(sfe->nameval, sfe->namelen);
    135		sbp->name = sfe->nameval;
    136		sbp->namelen = sfe->namelen;
    137		/* These are bytes, and both on-disk, don't endian-flip */
    138		sbp->valuelen = sfe->valuelen;
    139		sbp->flags = sfe->flags;
    140		sfe = xfs_attr_sf_nextentry(sfe);
    141		sbp++;
    142		nsbuf++;
    143	}
    144
    145	/*
    146	 * Sort the entries on hash then entno.
    147	 */
    148	xfs_sort(sbuf, nsbuf, sizeof(*sbuf), xfs_attr_shortform_compare);
    149
    150	/*
    151	 * Re-find our place IN THE SORTED LIST.
    152	 */
    153	count = 0;
    154	cursor->initted = 1;
    155	cursor->blkno = 0;
    156	for (sbp = sbuf, i = 0; i < nsbuf; i++, sbp++) {
    157		if (sbp->hash == cursor->hashval) {
    158			if (cursor->offset == count) {
    159				break;
    160			}
    161			count++;
    162		} else if (sbp->hash > cursor->hashval) {
    163			break;
    164		}
    165	}
    166	if (i == nsbuf)
    167		goto out;
    168
    169	/*
    170	 * Loop putting entries into the user buffer.
    171	 */
    172	for ( ; i < nsbuf; i++, sbp++) {
    173		if (cursor->hashval != sbp->hash) {
    174			cursor->hashval = sbp->hash;
    175			cursor->offset = 0;
    176		}
    177		if (XFS_IS_CORRUPT(context->dp->i_mount,
    178				   !xfs_attr_namecheck(sbp->name,
    179						       sbp->namelen))) {
    180			error = -EFSCORRUPTED;
    181			goto out;
    182		}
    183		context->put_listent(context,
    184				     sbp->flags,
    185				     sbp->name,
    186				     sbp->namelen,
    187				     sbp->valuelen);
    188		if (context->seen_enough)
    189			break;
    190		cursor->offset++;
    191	}
    192out:
    193	kmem_free(sbuf);
    194	return error;
    195}
    196
    197/*
    198 * We didn't find the block & hash mentioned in the cursor state, so
    199 * walk down the attr btree looking for the hash.
    200 */
    201STATIC int
    202xfs_attr_node_list_lookup(
    203	struct xfs_attr_list_context	*context,
    204	struct xfs_attrlist_cursor_kern	*cursor,
    205	struct xfs_buf			**pbp)
    206{
    207	struct xfs_da3_icnode_hdr	nodehdr;
    208	struct xfs_da_intnode		*node;
    209	struct xfs_da_node_entry	*btree;
    210	struct xfs_inode		*dp = context->dp;
    211	struct xfs_mount		*mp = dp->i_mount;
    212	struct xfs_trans		*tp = context->tp;
    213	struct xfs_buf			*bp;
    214	int				i;
    215	int				error = 0;
    216	unsigned int			expected_level = 0;
    217	uint16_t			magic;
    218
    219	ASSERT(*pbp == NULL);
    220	cursor->blkno = 0;
    221	for (;;) {
    222		error = xfs_da3_node_read(tp, dp, cursor->blkno, &bp,
    223				XFS_ATTR_FORK);
    224		if (error)
    225			return error;
    226		node = bp->b_addr;
    227		magic = be16_to_cpu(node->hdr.info.magic);
    228		if (magic == XFS_ATTR_LEAF_MAGIC ||
    229		    magic == XFS_ATTR3_LEAF_MAGIC)
    230			break;
    231		if (magic != XFS_DA_NODE_MAGIC &&
    232		    magic != XFS_DA3_NODE_MAGIC) {
    233			XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp,
    234					node, sizeof(*node));
    235			goto out_corruptbuf;
    236		}
    237
    238		xfs_da3_node_hdr_from_disk(mp, &nodehdr, node);
    239
    240		/* Tree taller than we can handle; bail out! */
    241		if (nodehdr.level >= XFS_DA_NODE_MAXDEPTH)
    242			goto out_corruptbuf;
    243
    244		/* Check the level from the root node. */
    245		if (cursor->blkno == 0)
    246			expected_level = nodehdr.level - 1;
    247		else if (expected_level != nodehdr.level)
    248			goto out_corruptbuf;
    249		else
    250			expected_level--;
    251
    252		btree = nodehdr.btree;
    253		for (i = 0; i < nodehdr.count; btree++, i++) {
    254			if (cursor->hashval <= be32_to_cpu(btree->hashval)) {
    255				cursor->blkno = be32_to_cpu(btree->before);
    256				trace_xfs_attr_list_node_descend(context,
    257						btree);
    258				break;
    259			}
    260		}
    261		xfs_trans_brelse(tp, bp);
    262
    263		if (i == nodehdr.count)
    264			return 0;
    265
    266		/* We can't point back to the root. */
    267		if (XFS_IS_CORRUPT(mp, cursor->blkno == 0))
    268			return -EFSCORRUPTED;
    269	}
    270
    271	if (expected_level != 0)
    272		goto out_corruptbuf;
    273
    274	*pbp = bp;
    275	return 0;
    276
    277out_corruptbuf:
    278	xfs_buf_mark_corrupt(bp);
    279	xfs_trans_brelse(tp, bp);
    280	return -EFSCORRUPTED;
    281}
    282
    283STATIC int
    284xfs_attr_node_list(
    285	struct xfs_attr_list_context	*context)
    286{
    287	struct xfs_attrlist_cursor_kern	*cursor = &context->cursor;
    288	struct xfs_attr3_icleaf_hdr	leafhdr;
    289	struct xfs_attr_leafblock	*leaf;
    290	struct xfs_da_intnode		*node;
    291	struct xfs_buf			*bp;
    292	struct xfs_inode		*dp = context->dp;
    293	struct xfs_mount		*mp = dp->i_mount;
    294	int				error = 0;
    295
    296	trace_xfs_attr_node_list(context);
    297
    298	cursor->initted = 1;
    299
    300	/*
    301	 * Do all sorts of validation on the passed-in cursor structure.
    302	 * If anything is amiss, ignore the cursor and look up the hashval
    303	 * starting from the btree root.
    304	 */
    305	bp = NULL;
    306	if (cursor->blkno > 0) {
    307		error = xfs_da3_node_read(context->tp, dp, cursor->blkno, &bp,
    308				XFS_ATTR_FORK);
    309		if ((error != 0) && (error != -EFSCORRUPTED))
    310			return error;
    311		if (bp) {
    312			struct xfs_attr_leaf_entry *entries;
    313
    314			node = bp->b_addr;
    315			switch (be16_to_cpu(node->hdr.info.magic)) {
    316			case XFS_DA_NODE_MAGIC:
    317			case XFS_DA3_NODE_MAGIC:
    318				trace_xfs_attr_list_wrong_blk(context);
    319				xfs_trans_brelse(context->tp, bp);
    320				bp = NULL;
    321				break;
    322			case XFS_ATTR_LEAF_MAGIC:
    323			case XFS_ATTR3_LEAF_MAGIC:
    324				leaf = bp->b_addr;
    325				xfs_attr3_leaf_hdr_from_disk(mp->m_attr_geo,
    326							     &leafhdr, leaf);
    327				entries = xfs_attr3_leaf_entryp(leaf);
    328				if (cursor->hashval > be32_to_cpu(
    329						entries[leafhdr.count - 1].hashval)) {
    330					trace_xfs_attr_list_wrong_blk(context);
    331					xfs_trans_brelse(context->tp, bp);
    332					bp = NULL;
    333				} else if (cursor->hashval <= be32_to_cpu(
    334						entries[0].hashval)) {
    335					trace_xfs_attr_list_wrong_blk(context);
    336					xfs_trans_brelse(context->tp, bp);
    337					bp = NULL;
    338				}
    339				break;
    340			default:
    341				trace_xfs_attr_list_wrong_blk(context);
    342				xfs_trans_brelse(context->tp, bp);
    343				bp = NULL;
    344			}
    345		}
    346	}
    347
    348	/*
    349	 * We did not find what we expected given the cursor's contents,
    350	 * so we start from the top and work down based on the hash value.
    351	 * Note that start of node block is same as start of leaf block.
    352	 */
    353	if (bp == NULL) {
    354		error = xfs_attr_node_list_lookup(context, cursor, &bp);
    355		if (error || !bp)
    356			return error;
    357	}
    358	ASSERT(bp != NULL);
    359
    360	/*
    361	 * Roll upward through the blocks, processing each leaf block in
    362	 * order.  As long as there is space in the result buffer, keep
    363	 * adding the information.
    364	 */
    365	for (;;) {
    366		leaf = bp->b_addr;
    367		error = xfs_attr3_leaf_list_int(bp, context);
    368		if (error)
    369			break;
    370		xfs_attr3_leaf_hdr_from_disk(mp->m_attr_geo, &leafhdr, leaf);
    371		if (context->seen_enough || leafhdr.forw == 0)
    372			break;
    373		cursor->blkno = leafhdr.forw;
    374		xfs_trans_brelse(context->tp, bp);
    375		error = xfs_attr3_leaf_read(context->tp, dp, cursor->blkno,
    376					    &bp);
    377		if (error)
    378			return error;
    379	}
    380	xfs_trans_brelse(context->tp, bp);
    381	return error;
    382}
    383
    384/*
    385 * Copy out attribute list entries for attr_list(), for leaf attribute lists.
    386 */
    387int
    388xfs_attr3_leaf_list_int(
    389	struct xfs_buf			*bp,
    390	struct xfs_attr_list_context	*context)
    391{
    392	struct xfs_attrlist_cursor_kern	*cursor = &context->cursor;
    393	struct xfs_attr_leafblock	*leaf;
    394	struct xfs_attr3_icleaf_hdr	ichdr;
    395	struct xfs_attr_leaf_entry	*entries;
    396	struct xfs_attr_leaf_entry	*entry;
    397	int				i;
    398	struct xfs_mount		*mp = context->dp->i_mount;
    399
    400	trace_xfs_attr_list_leaf(context);
    401
    402	leaf = bp->b_addr;
    403	xfs_attr3_leaf_hdr_from_disk(mp->m_attr_geo, &ichdr, leaf);
    404	entries = xfs_attr3_leaf_entryp(leaf);
    405
    406	cursor->initted = 1;
    407
    408	/*
    409	 * Re-find our place in the leaf block if this is a new syscall.
    410	 */
    411	if (context->resynch) {
    412		entry = &entries[0];
    413		for (i = 0; i < ichdr.count; entry++, i++) {
    414			if (be32_to_cpu(entry->hashval) == cursor->hashval) {
    415				if (cursor->offset == context->dupcnt) {
    416					context->dupcnt = 0;
    417					break;
    418				}
    419				context->dupcnt++;
    420			} else if (be32_to_cpu(entry->hashval) >
    421					cursor->hashval) {
    422				context->dupcnt = 0;
    423				break;
    424			}
    425		}
    426		if (i == ichdr.count) {
    427			trace_xfs_attr_list_notfound(context);
    428			return 0;
    429		}
    430	} else {
    431		entry = &entries[0];
    432		i = 0;
    433	}
    434	context->resynch = 0;
    435
    436	/*
    437	 * We have found our place, start copying out the new attributes.
    438	 */
    439	for (; i < ichdr.count; entry++, i++) {
    440		char *name;
    441		int namelen, valuelen;
    442
    443		if (be32_to_cpu(entry->hashval) != cursor->hashval) {
    444			cursor->hashval = be32_to_cpu(entry->hashval);
    445			cursor->offset = 0;
    446		}
    447
    448		if ((entry->flags & XFS_ATTR_INCOMPLETE) &&
    449		    !context->allow_incomplete)
    450			continue;
    451
    452		if (entry->flags & XFS_ATTR_LOCAL) {
    453			xfs_attr_leaf_name_local_t *name_loc;
    454
    455			name_loc = xfs_attr3_leaf_name_local(leaf, i);
    456			name = name_loc->nameval;
    457			namelen = name_loc->namelen;
    458			valuelen = be16_to_cpu(name_loc->valuelen);
    459		} else {
    460			xfs_attr_leaf_name_remote_t *name_rmt;
    461
    462			name_rmt = xfs_attr3_leaf_name_remote(leaf, i);
    463			name = name_rmt->name;
    464			namelen = name_rmt->namelen;
    465			valuelen = be32_to_cpu(name_rmt->valuelen);
    466		}
    467
    468		if (XFS_IS_CORRUPT(context->dp->i_mount,
    469				   !xfs_attr_namecheck(name, namelen)))
    470			return -EFSCORRUPTED;
    471		context->put_listent(context, entry->flags,
    472					      name, namelen, valuelen);
    473		if (context->seen_enough)
    474			break;
    475		cursor->offset++;
    476	}
    477	trace_xfs_attr_list_leaf_end(context);
    478	return 0;
    479}
    480
    481/*
    482 * Copy out attribute entries for attr_list(), for leaf attribute lists.
    483 */
    484STATIC int
    485xfs_attr_leaf_list(
    486	struct xfs_attr_list_context	*context)
    487{
    488	struct xfs_buf			*bp;
    489	int				error;
    490
    491	trace_xfs_attr_leaf_list(context);
    492
    493	context->cursor.blkno = 0;
    494	error = xfs_attr3_leaf_read(context->tp, context->dp, 0, &bp);
    495	if (error)
    496		return error;
    497
    498	error = xfs_attr3_leaf_list_int(bp, context);
    499	xfs_trans_brelse(context->tp, bp);
    500	return error;
    501}
    502
    503int
    504xfs_attr_list_ilocked(
    505	struct xfs_attr_list_context	*context)
    506{
    507	struct xfs_inode		*dp = context->dp;
    508
    509	ASSERT(xfs_isilocked(dp, XFS_ILOCK_SHARED | XFS_ILOCK_EXCL));
    510
    511	/*
    512	 * Decide on what work routines to call based on the inode size.
    513	 */
    514	if (!xfs_inode_hasattr(dp))
    515		return 0;
    516	if (dp->i_afp->if_format == XFS_DINODE_FMT_LOCAL)
    517		return xfs_attr_shortform_list(context);
    518	if (xfs_attr_is_leaf(dp))
    519		return xfs_attr_leaf_list(context);
    520	return xfs_attr_node_list(context);
    521}
    522
    523int
    524xfs_attr_list(
    525	struct xfs_attr_list_context	*context)
    526{
    527	struct xfs_inode		*dp = context->dp;
    528	uint				lock_mode;
    529	int				error;
    530
    531	XFS_STATS_INC(dp->i_mount, xs_attr_list);
    532
    533	if (xfs_is_shutdown(dp->i_mount))
    534		return -EIO;
    535
    536	lock_mode = xfs_ilock_attr_map_shared(dp);
    537	error = xfs_attr_list_ilocked(context);
    538	xfs_iunlock(dp, lock_mode);
    539	return error;
    540}