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

attr.c (14170B)


      1// SPDX-License-Identifier: GPL-2.0+
      2/*
      3 * Copyright (C) 2017 Oracle.  All Rights Reserved.
      4 * Author: Darrick J. Wong <darrick.wong@oracle.com>
      5 */
      6#include "xfs.h"
      7#include "xfs_fs.h"
      8#include "xfs_shared.h"
      9#include "xfs_format.h"
     10#include "xfs_trans_resv.h"
     11#include "xfs_mount.h"
     12#include "xfs_log_format.h"
     13#include "xfs_inode.h"
     14#include "xfs_da_format.h"
     15#include "xfs_da_btree.h"
     16#include "xfs_attr.h"
     17#include "xfs_attr_leaf.h"
     18#include "scrub/scrub.h"
     19#include "scrub/common.h"
     20#include "scrub/dabtree.h"
     21#include "scrub/attr.h"
     22
     23/*
     24 * Allocate enough memory to hold an attr value and attr block bitmaps,
     25 * reallocating the buffer if necessary.  Buffer contents are not preserved
     26 * across a reallocation.
     27 */
     28static int
     29xchk_setup_xattr_buf(
     30	struct xfs_scrub	*sc,
     31	size_t			value_size,
     32	gfp_t			flags)
     33{
     34	size_t			sz;
     35	struct xchk_xattr_buf	*ab = sc->buf;
     36
     37	/*
     38	 * We need enough space to read an xattr value from the file or enough
     39	 * space to hold three copies of the xattr free space bitmap.  We don't
     40	 * need the buffer space for both purposes at the same time.
     41	 */
     42	sz = 3 * sizeof(long) * BITS_TO_LONGS(sc->mp->m_attr_geo->blksize);
     43	sz = max_t(size_t, sz, value_size);
     44
     45	/*
     46	 * If there's already a buffer, figure out if we need to reallocate it
     47	 * to accommodate a larger size.
     48	 */
     49	if (ab) {
     50		if (sz <= ab->sz)
     51			return 0;
     52		kmem_free(ab);
     53		sc->buf = NULL;
     54	}
     55
     56	/*
     57	 * Don't zero the buffer upon allocation to avoid runtime overhead.
     58	 * All users must be careful never to read uninitialized contents.
     59	 */
     60	ab = kvmalloc(sizeof(*ab) + sz, flags);
     61	if (!ab)
     62		return -ENOMEM;
     63
     64	ab->sz = sz;
     65	sc->buf = ab;
     66	return 0;
     67}
     68
     69/* Set us up to scrub an inode's extended attributes. */
     70int
     71xchk_setup_xattr(
     72	struct xfs_scrub	*sc)
     73{
     74	int			error;
     75
     76	/*
     77	 * We failed to get memory while checking attrs, so this time try to
     78	 * get all the memory we're ever going to need.  Allocate the buffer
     79	 * without the inode lock held, which means we can sleep.
     80	 */
     81	if (sc->flags & XCHK_TRY_HARDER) {
     82		error = xchk_setup_xattr_buf(sc, XATTR_SIZE_MAX, GFP_KERNEL);
     83		if (error)
     84			return error;
     85	}
     86
     87	return xchk_setup_inode_contents(sc, 0);
     88}
     89
     90/* Extended Attributes */
     91
     92struct xchk_xattr {
     93	struct xfs_attr_list_context	context;
     94	struct xfs_scrub		*sc;
     95};
     96
     97/*
     98 * Check that an extended attribute key can be looked up by hash.
     99 *
    100 * We use the XFS attribute list iterator (i.e. xfs_attr_list_ilocked)
    101 * to call this function for every attribute key in an inode.  Once
    102 * we're here, we load the attribute value to see if any errors happen,
    103 * or if we get more or less data than we expected.
    104 */
    105static void
    106xchk_xattr_listent(
    107	struct xfs_attr_list_context	*context,
    108	int				flags,
    109	unsigned char			*name,
    110	int				namelen,
    111	int				valuelen)
    112{
    113	struct xchk_xattr		*sx;
    114	struct xfs_da_args		args = { NULL };
    115	int				error = 0;
    116
    117	sx = container_of(context, struct xchk_xattr, context);
    118
    119	if (xchk_should_terminate(sx->sc, &error)) {
    120		context->seen_enough = error;
    121		return;
    122	}
    123
    124	if (flags & XFS_ATTR_INCOMPLETE) {
    125		/* Incomplete attr key, just mark the inode for preening. */
    126		xchk_ino_set_preen(sx->sc, context->dp->i_ino);
    127		return;
    128	}
    129
    130	/* Does this name make sense? */
    131	if (!xfs_attr_namecheck(name, namelen)) {
    132		xchk_fblock_set_corrupt(sx->sc, XFS_ATTR_FORK, args.blkno);
    133		return;
    134	}
    135
    136	/*
    137	 * Try to allocate enough memory to extrat the attr value.  If that
    138	 * doesn't work, we overload the seen_enough variable to convey
    139	 * the error message back to the main scrub function.
    140	 */
    141	error = xchk_setup_xattr_buf(sx->sc, valuelen,
    142			GFP_KERNEL | __GFP_RETRY_MAYFAIL);
    143	if (error == -ENOMEM)
    144		error = -EDEADLOCK;
    145	if (error) {
    146		context->seen_enough = error;
    147		return;
    148	}
    149
    150	args.op_flags = XFS_DA_OP_NOTIME;
    151	args.attr_filter = flags & XFS_ATTR_NSP_ONDISK_MASK;
    152	args.geo = context->dp->i_mount->m_attr_geo;
    153	args.whichfork = XFS_ATTR_FORK;
    154	args.dp = context->dp;
    155	args.name = name;
    156	args.namelen = namelen;
    157	args.hashval = xfs_da_hashname(args.name, args.namelen);
    158	args.trans = context->tp;
    159	args.value = xchk_xattr_valuebuf(sx->sc);
    160	args.valuelen = valuelen;
    161
    162	error = xfs_attr_get_ilocked(&args);
    163	/* ENODATA means the hash lookup failed and the attr is bad */
    164	if (error == -ENODATA)
    165		error = -EFSCORRUPTED;
    166	if (!xchk_fblock_process_error(sx->sc, XFS_ATTR_FORK, args.blkno,
    167			&error))
    168		goto fail_xref;
    169	if (args.valuelen != valuelen)
    170		xchk_fblock_set_corrupt(sx->sc, XFS_ATTR_FORK,
    171					     args.blkno);
    172fail_xref:
    173	if (sx->sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
    174		context->seen_enough = 1;
    175	return;
    176}
    177
    178/*
    179 * Mark a range [start, start+len) in this map.  Returns true if the
    180 * region was free, and false if there's a conflict or a problem.
    181 *
    182 * Within a char, the lowest bit of the char represents the byte with
    183 * the smallest address
    184 */
    185STATIC bool
    186xchk_xattr_set_map(
    187	struct xfs_scrub	*sc,
    188	unsigned long		*map,
    189	unsigned int		start,
    190	unsigned int		len)
    191{
    192	unsigned int		mapsize = sc->mp->m_attr_geo->blksize;
    193	bool			ret = true;
    194
    195	if (start >= mapsize)
    196		return false;
    197	if (start + len > mapsize) {
    198		len = mapsize - start;
    199		ret = false;
    200	}
    201
    202	if (find_next_bit(map, mapsize, start) < start + len)
    203		ret = false;
    204	bitmap_set(map, start, len);
    205
    206	return ret;
    207}
    208
    209/*
    210 * Check the leaf freemap from the usage bitmap.  Returns false if the
    211 * attr freemap has problems or points to used space.
    212 */
    213STATIC bool
    214xchk_xattr_check_freemap(
    215	struct xfs_scrub		*sc,
    216	unsigned long			*map,
    217	struct xfs_attr3_icleaf_hdr	*leafhdr)
    218{
    219	unsigned long			*freemap = xchk_xattr_freemap(sc);
    220	unsigned long			*dstmap = xchk_xattr_dstmap(sc);
    221	unsigned int			mapsize = sc->mp->m_attr_geo->blksize;
    222	int				i;
    223
    224	/* Construct bitmap of freemap contents. */
    225	bitmap_zero(freemap, mapsize);
    226	for (i = 0; i < XFS_ATTR_LEAF_MAPSIZE; i++) {
    227		if (!xchk_xattr_set_map(sc, freemap,
    228				leafhdr->freemap[i].base,
    229				leafhdr->freemap[i].size))
    230			return false;
    231	}
    232
    233	/* Look for bits that are set in freemap and are marked in use. */
    234	return bitmap_and(dstmap, freemap, map, mapsize) == 0;
    235}
    236
    237/*
    238 * Check this leaf entry's relations to everything else.
    239 * Returns the number of bytes used for the name/value data.
    240 */
    241STATIC void
    242xchk_xattr_entry(
    243	struct xchk_da_btree		*ds,
    244	int				level,
    245	char				*buf_end,
    246	struct xfs_attr_leafblock	*leaf,
    247	struct xfs_attr3_icleaf_hdr	*leafhdr,
    248	struct xfs_attr_leaf_entry	*ent,
    249	int				idx,
    250	unsigned int			*usedbytes,
    251	__u32				*last_hashval)
    252{
    253	struct xfs_mount		*mp = ds->state->mp;
    254	unsigned long			*usedmap = xchk_xattr_usedmap(ds->sc);
    255	char				*name_end;
    256	struct xfs_attr_leaf_name_local	*lentry;
    257	struct xfs_attr_leaf_name_remote *rentry;
    258	unsigned int			nameidx;
    259	unsigned int			namesize;
    260
    261	if (ent->pad2 != 0)
    262		xchk_da_set_corrupt(ds, level);
    263
    264	/* Hash values in order? */
    265	if (be32_to_cpu(ent->hashval) < *last_hashval)
    266		xchk_da_set_corrupt(ds, level);
    267	*last_hashval = be32_to_cpu(ent->hashval);
    268
    269	nameidx = be16_to_cpu(ent->nameidx);
    270	if (nameidx < leafhdr->firstused ||
    271	    nameidx >= mp->m_attr_geo->blksize) {
    272		xchk_da_set_corrupt(ds, level);
    273		return;
    274	}
    275
    276	/* Check the name information. */
    277	if (ent->flags & XFS_ATTR_LOCAL) {
    278		lentry = xfs_attr3_leaf_name_local(leaf, idx);
    279		namesize = xfs_attr_leaf_entsize_local(lentry->namelen,
    280				be16_to_cpu(lentry->valuelen));
    281		name_end = (char *)lentry + namesize;
    282		if (lentry->namelen == 0)
    283			xchk_da_set_corrupt(ds, level);
    284	} else {
    285		rentry = xfs_attr3_leaf_name_remote(leaf, idx);
    286		namesize = xfs_attr_leaf_entsize_remote(rentry->namelen);
    287		name_end = (char *)rentry + namesize;
    288		if (rentry->namelen == 0 || rentry->valueblk == 0)
    289			xchk_da_set_corrupt(ds, level);
    290	}
    291	if (name_end > buf_end)
    292		xchk_da_set_corrupt(ds, level);
    293
    294	if (!xchk_xattr_set_map(ds->sc, usedmap, nameidx, namesize))
    295		xchk_da_set_corrupt(ds, level);
    296	if (!(ds->sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT))
    297		*usedbytes += namesize;
    298}
    299
    300/* Scrub an attribute leaf. */
    301STATIC int
    302xchk_xattr_block(
    303	struct xchk_da_btree		*ds,
    304	int				level)
    305{
    306	struct xfs_attr3_icleaf_hdr	leafhdr;
    307	struct xfs_mount		*mp = ds->state->mp;
    308	struct xfs_da_state_blk		*blk = &ds->state->path.blk[level];
    309	struct xfs_buf			*bp = blk->bp;
    310	xfs_dablk_t			*last_checked = ds->private;
    311	struct xfs_attr_leafblock	*leaf = bp->b_addr;
    312	struct xfs_attr_leaf_entry	*ent;
    313	struct xfs_attr_leaf_entry	*entries;
    314	unsigned long			*usedmap;
    315	char				*buf_end;
    316	size_t				off;
    317	__u32				last_hashval = 0;
    318	unsigned int			usedbytes = 0;
    319	unsigned int			hdrsize;
    320	int				i;
    321	int				error;
    322
    323	if (*last_checked == blk->blkno)
    324		return 0;
    325
    326	/* Allocate memory for block usage checking. */
    327	error = xchk_setup_xattr_buf(ds->sc, 0,
    328			GFP_KERNEL | __GFP_RETRY_MAYFAIL);
    329	if (error == -ENOMEM)
    330		return -EDEADLOCK;
    331	if (error)
    332		return error;
    333	usedmap = xchk_xattr_usedmap(ds->sc);
    334
    335	*last_checked = blk->blkno;
    336	bitmap_zero(usedmap, mp->m_attr_geo->blksize);
    337
    338	/* Check all the padding. */
    339	if (xfs_has_crc(ds->sc->mp)) {
    340		struct xfs_attr3_leafblock	*leaf = bp->b_addr;
    341
    342		if (leaf->hdr.pad1 != 0 || leaf->hdr.pad2 != 0 ||
    343		    leaf->hdr.info.hdr.pad != 0)
    344			xchk_da_set_corrupt(ds, level);
    345	} else {
    346		if (leaf->hdr.pad1 != 0 || leaf->hdr.info.pad != 0)
    347			xchk_da_set_corrupt(ds, level);
    348	}
    349
    350	/* Check the leaf header */
    351	xfs_attr3_leaf_hdr_from_disk(mp->m_attr_geo, &leafhdr, leaf);
    352	hdrsize = xfs_attr3_leaf_hdr_size(leaf);
    353
    354	if (leafhdr.usedbytes > mp->m_attr_geo->blksize)
    355		xchk_da_set_corrupt(ds, level);
    356	if (leafhdr.firstused > mp->m_attr_geo->blksize)
    357		xchk_da_set_corrupt(ds, level);
    358	if (leafhdr.firstused < hdrsize)
    359		xchk_da_set_corrupt(ds, level);
    360	if (!xchk_xattr_set_map(ds->sc, usedmap, 0, hdrsize))
    361		xchk_da_set_corrupt(ds, level);
    362
    363	if (ds->sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
    364		goto out;
    365
    366	entries = xfs_attr3_leaf_entryp(leaf);
    367	if ((char *)&entries[leafhdr.count] > (char *)leaf + leafhdr.firstused)
    368		xchk_da_set_corrupt(ds, level);
    369
    370	buf_end = (char *)bp->b_addr + mp->m_attr_geo->blksize;
    371	for (i = 0, ent = entries; i < leafhdr.count; ent++, i++) {
    372		/* Mark the leaf entry itself. */
    373		off = (char *)ent - (char *)leaf;
    374		if (!xchk_xattr_set_map(ds->sc, usedmap, off,
    375				sizeof(xfs_attr_leaf_entry_t))) {
    376			xchk_da_set_corrupt(ds, level);
    377			goto out;
    378		}
    379
    380		/* Check the entry and nameval. */
    381		xchk_xattr_entry(ds, level, buf_end, leaf, &leafhdr,
    382				ent, i, &usedbytes, &last_hashval);
    383
    384		if (ds->sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
    385			goto out;
    386	}
    387
    388	if (!xchk_xattr_check_freemap(ds->sc, usedmap, &leafhdr))
    389		xchk_da_set_corrupt(ds, level);
    390
    391	if (leafhdr.usedbytes != usedbytes)
    392		xchk_da_set_corrupt(ds, level);
    393
    394out:
    395	return 0;
    396}
    397
    398/* Scrub a attribute btree record. */
    399STATIC int
    400xchk_xattr_rec(
    401	struct xchk_da_btree		*ds,
    402	int				level)
    403{
    404	struct xfs_mount		*mp = ds->state->mp;
    405	struct xfs_da_state_blk		*blk = &ds->state->path.blk[level];
    406	struct xfs_attr_leaf_name_local	*lentry;
    407	struct xfs_attr_leaf_name_remote	*rentry;
    408	struct xfs_buf			*bp;
    409	struct xfs_attr_leaf_entry	*ent;
    410	xfs_dahash_t			calc_hash;
    411	xfs_dahash_t			hash;
    412	int				nameidx;
    413	int				hdrsize;
    414	unsigned int			badflags;
    415	int				error;
    416
    417	ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
    418
    419	ent = xfs_attr3_leaf_entryp(blk->bp->b_addr) + blk->index;
    420
    421	/* Check the whole block, if necessary. */
    422	error = xchk_xattr_block(ds, level);
    423	if (error)
    424		goto out;
    425	if (ds->sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
    426		goto out;
    427
    428	/* Check the hash of the entry. */
    429	error = xchk_da_btree_hash(ds, level, &ent->hashval);
    430	if (error)
    431		goto out;
    432
    433	/* Find the attr entry's location. */
    434	bp = blk->bp;
    435	hdrsize = xfs_attr3_leaf_hdr_size(bp->b_addr);
    436	nameidx = be16_to_cpu(ent->nameidx);
    437	if (nameidx < hdrsize || nameidx >= mp->m_attr_geo->blksize) {
    438		xchk_da_set_corrupt(ds, level);
    439		goto out;
    440	}
    441
    442	/* Retrieve the entry and check it. */
    443	hash = be32_to_cpu(ent->hashval);
    444	badflags = ~(XFS_ATTR_LOCAL | XFS_ATTR_ROOT | XFS_ATTR_SECURE |
    445			XFS_ATTR_INCOMPLETE);
    446	if ((ent->flags & badflags) != 0)
    447		xchk_da_set_corrupt(ds, level);
    448	if (ent->flags & XFS_ATTR_LOCAL) {
    449		lentry = (struct xfs_attr_leaf_name_local *)
    450				(((char *)bp->b_addr) + nameidx);
    451		if (lentry->namelen <= 0) {
    452			xchk_da_set_corrupt(ds, level);
    453			goto out;
    454		}
    455		calc_hash = xfs_da_hashname(lentry->nameval, lentry->namelen);
    456	} else {
    457		rentry = (struct xfs_attr_leaf_name_remote *)
    458				(((char *)bp->b_addr) + nameidx);
    459		if (rentry->namelen <= 0) {
    460			xchk_da_set_corrupt(ds, level);
    461			goto out;
    462		}
    463		calc_hash = xfs_da_hashname(rentry->name, rentry->namelen);
    464	}
    465	if (calc_hash != hash)
    466		xchk_da_set_corrupt(ds, level);
    467
    468out:
    469	return error;
    470}
    471
    472/* Scrub the extended attribute metadata. */
    473int
    474xchk_xattr(
    475	struct xfs_scrub		*sc)
    476{
    477	struct xchk_xattr		sx;
    478	xfs_dablk_t			last_checked = -1U;
    479	int				error = 0;
    480
    481	if (!xfs_inode_hasattr(sc->ip))
    482		return -ENOENT;
    483
    484	memset(&sx, 0, sizeof(sx));
    485	/* Check attribute tree structure */
    486	error = xchk_da_btree(sc, XFS_ATTR_FORK, xchk_xattr_rec,
    487			&last_checked);
    488	if (error)
    489		goto out;
    490
    491	if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
    492		goto out;
    493
    494	/* Check that every attr key can also be looked up by hash. */
    495	sx.context.dp = sc->ip;
    496	sx.context.resynch = 1;
    497	sx.context.put_listent = xchk_xattr_listent;
    498	sx.context.tp = sc->tp;
    499	sx.context.allow_incomplete = true;
    500	sx.sc = sc;
    501
    502	/*
    503	 * Look up every xattr in this file by name.
    504	 *
    505	 * Use the backend implementation of xfs_attr_list to call
    506	 * xchk_xattr_listent on every attribute key in this inode.
    507	 * In other words, we use the same iterator/callback mechanism
    508	 * that listattr uses to scrub extended attributes, though in our
    509	 * _listent function, we check the value of the attribute.
    510	 *
    511	 * The VFS only locks i_rwsem when modifying attrs, so keep all
    512	 * three locks held because that's the only way to ensure we're
    513	 * the only thread poking into the da btree.  We traverse the da
    514	 * btree while holding a leaf buffer locked for the xattr name
    515	 * iteration, which doesn't really follow the usual buffer
    516	 * locking order.
    517	 */
    518	error = xfs_attr_list_ilocked(&sx.context);
    519	if (!xchk_fblock_process_error(sc, XFS_ATTR_FORK, 0, &error))
    520		goto out;
    521
    522	/* Did our listent function try to return any errors? */
    523	if (sx.context.seen_enough < 0)
    524		error = sx.context.seen_enough;
    525out:
    526	return error;
    527}