Commit f4887fbc authored by Darrick J. Wong's avatar Darrick J. Wong
Browse files

xfs: validate attr leaf buffer owners



Create a leaf block header checking function to validate the owner field
of xattr leaf blocks.

Signed-off-by: default avatarDarrick J. Wong <djwong@kernel.org>
Reviewed-by: default avatarChristoph Hellwig <hch@lst.de>
parent 33c028ff
Loading
Loading
Loading
Loading
+5 −5
Original line number Diff line number Diff line
@@ -649,8 +649,8 @@ xfs_attr_leaf_remove_attr(
	int				forkoff;
	int				error;

	error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno,
				   &bp);
	error = xfs_attr3_leaf_read(args->trans, args->dp, args->owner,
			args->blkno, &bp);
	if (error)
		return error;

@@ -681,7 +681,7 @@ xfs_attr_leaf_shrink(
	if (!xfs_attr_is_leaf(dp))
		return 0;

	error = xfs_attr3_leaf_read(args->trans, args->dp, 0, &bp);
	error = xfs_attr3_leaf_read(args->trans, args->dp, args->owner, 0, &bp);
	if (error)
		return error;

@@ -1158,7 +1158,7 @@ xfs_attr_leaf_try_add(
	struct xfs_buf		*bp;
	int			error;

	error = xfs_attr3_leaf_read(args->trans, args->dp, 0, &bp);
	error = xfs_attr3_leaf_read(args->trans, args->dp, args->owner, 0, &bp);
	if (error)
		return error;

@@ -1206,7 +1206,7 @@ xfs_attr_leaf_hasname(
{
	int                     error = 0;

	error = xfs_attr3_leaf_read(args->trans, args->dp, 0, bp);
	error = xfs_attr3_leaf_read(args->trans, args->dp, args->owner, 0, bp);
	if (error)
		return error;

+47 −9
Original line number Diff line number Diff line
@@ -388,6 +388,27 @@ xfs_attr3_leaf_verify(
	return NULL;
}

xfs_failaddr_t
xfs_attr3_leaf_header_check(
	struct xfs_buf		*bp,
	xfs_ino_t		owner)
{
	struct xfs_mount	*mp = bp->b_mount;

	if (xfs_has_crc(mp)) {
		struct xfs_attr3_leafblock *hdr3 = bp->b_addr;

		if (hdr3->hdr.info.hdr.magic !=
				cpu_to_be16(XFS_ATTR3_LEAF_MAGIC))
			return __this_address;

		if (be64_to_cpu(hdr3->hdr.info.owner) != owner)
			return __this_address;
	}

	return NULL;
}

static void
xfs_attr3_leaf_write_verify(
	struct xfs_buf	*bp)
@@ -448,16 +469,30 @@ int
xfs_attr3_leaf_read(
	struct xfs_trans	*tp,
	struct xfs_inode	*dp,
	xfs_ino_t		owner,
	xfs_dablk_t		bno,
	struct xfs_buf		**bpp)
{
	xfs_failaddr_t		fa;
	int			err;

	err = xfs_da_read_buf(tp, dp, bno, 0, bpp, XFS_ATTR_FORK,
			&xfs_attr3_leaf_buf_ops);
	if (!err && tp && *bpp)
		xfs_trans_buf_set_type(tp, *bpp, XFS_BLFT_ATTR_LEAF_BUF);
	if (err || !(*bpp))
		return err;

	fa = xfs_attr3_leaf_header_check(*bpp, owner);
	if (fa) {
		__xfs_buf_mark_corrupt(*bpp, fa);
		xfs_trans_brelse(tp, *bpp);
		*bpp = NULL;
		xfs_dirattr_mark_sick(dp, XFS_ATTR_FORK);
		return -EFSCORRUPTED;
	}

	if (tp)
		xfs_trans_buf_set_type(tp, *bpp, XFS_BLFT_ATTR_LEAF_BUF);
	return 0;
}

/*========================================================================
@@ -1160,7 +1195,7 @@ xfs_attr3_leaf_to_node(
	error = xfs_da_grow_inode(args, &blkno);
	if (error)
		goto out;
	error = xfs_attr3_leaf_read(args->trans, dp, 0, &bp1);
	error = xfs_attr3_leaf_read(args->trans, dp, args->owner, 0, &bp1);
	if (error)
		goto out;

@@ -1995,7 +2030,7 @@ xfs_attr3_leaf_toosmall(
		if (blkno == 0)
			continue;
		error = xfs_attr3_leaf_read(state->args->trans, state->args->dp,
					blkno, &bp);
					state->args->owner, blkno, &bp);
		if (error)
			return error;

@@ -2717,7 +2752,8 @@ xfs_attr3_leaf_clearflag(
	/*
	 * Set up the operation.
	 */
	error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno, &bp);
	error = xfs_attr3_leaf_read(args->trans, args->dp, args->owner,
			args->blkno, &bp);
	if (error)
		return error;

@@ -2781,7 +2817,8 @@ xfs_attr3_leaf_setflag(
	/*
	 * Set up the operation.
	 */
	error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno, &bp);
	error = xfs_attr3_leaf_read(args->trans, args->dp, args->owner,
			args->blkno, &bp);
	if (error)
		return error;

@@ -2840,7 +2877,8 @@ xfs_attr3_leaf_flipflags(
	/*
	 * Read the block containing the "old" attr
	 */
	error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno, &bp1);
	error = xfs_attr3_leaf_read(args->trans, args->dp, args->owner,
			args->blkno, &bp1);
	if (error)
		return error;

@@ -2848,8 +2886,8 @@ xfs_attr3_leaf_flipflags(
	 * Read the block containing the "new" attr, if it is different
	 */
	if (args->blkno2 != args->blkno) {
		error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno2,
					   &bp2);
		error = xfs_attr3_leaf_read(args->trans, args->dp, args->owner,
				args->blkno2, &bp2);
		if (error)
			return error;
	} else {
+3 −1
Original line number Diff line number Diff line
@@ -98,12 +98,14 @@ int xfs_attr_leaf_order(struct xfs_buf *leaf1_bp,
				   struct xfs_buf *leaf2_bp);
int	xfs_attr_leaf_newentsize(struct xfs_da_args *args, int *local);
int	xfs_attr3_leaf_read(struct xfs_trans *tp, struct xfs_inode *dp,
			xfs_dablk_t bno, struct xfs_buf **bpp);
			xfs_ino_t owner, xfs_dablk_t bno, struct xfs_buf **bpp);
void	xfs_attr3_leaf_hdr_from_disk(struct xfs_da_geometry *geo,
				     struct xfs_attr3_icleaf_hdr *to,
				     struct xfs_attr_leafblock *from);
void	xfs_attr3_leaf_hdr_to_disk(struct xfs_da_geometry *geo,
				   struct xfs_attr_leafblock *to,
				   struct xfs_attr3_icleaf_hdr *from);
xfs_failaddr_t xfs_attr3_leaf_header_check(struct xfs_buf *bp,
		xfs_ino_t owner);

#endif	/* __XFS_ATTR_LEAF_H__ */
+42 −0
Original line number Diff line number Diff line
@@ -252,6 +252,25 @@ xfs_da3_node_verify(
	return NULL;
}

xfs_failaddr_t
xfs_da3_header_check(
	struct xfs_buf		*bp,
	xfs_ino_t		owner)
{
	struct xfs_mount	*mp = bp->b_mount;
	struct xfs_da_blkinfo	*hdr = bp->b_addr;

	if (!xfs_has_crc(mp))
		return NULL;

	switch (hdr->magic) {
	case cpu_to_be16(XFS_ATTR3_LEAF_MAGIC):
		return xfs_attr3_leaf_header_check(bp, owner);
	}

	return NULL;
}

static void
xfs_da3_node_write_verify(
	struct xfs_buf	*bp)
@@ -1591,6 +1610,7 @@ xfs_da3_node_lookup_int(
	struct xfs_da_node_entry *btree;
	struct xfs_da3_icnode_hdr nodehdr;
	struct xfs_da_args	*args;
	xfs_failaddr_t		fa;
	xfs_dablk_t		blkno;
	xfs_dahash_t		hashval;
	xfs_dahash_t		btreehashval;
@@ -1629,6 +1649,12 @@ xfs_da3_node_lookup_int(

		if (magic == XFS_ATTR_LEAF_MAGIC ||
		    magic == XFS_ATTR3_LEAF_MAGIC) {
			fa = xfs_attr3_leaf_header_check(blk->bp, args->owner);
			if (fa) {
				__xfs_buf_mark_corrupt(blk->bp, fa);
				xfs_da_mark_sick(args);
				return -EFSCORRUPTED;
			}
			blk->magic = XFS_ATTR_LEAF_MAGIC;
			blk->hashval = xfs_attr_leaf_lasthash(blk->bp, NULL);
			break;
@@ -1996,6 +2022,7 @@ xfs_da3_path_shift(
	struct xfs_da_node_entry *btree;
	struct xfs_da3_icnode_hdr nodehdr;
	struct xfs_buf		*bp;
	xfs_failaddr_t		fa;
	xfs_dablk_t		blkno = 0;
	int			level;
	int			error;
@@ -2087,6 +2114,12 @@ xfs_da3_path_shift(
			break;
		case XFS_ATTR_LEAF_MAGIC:
		case XFS_ATTR3_LEAF_MAGIC:
			fa = xfs_attr3_leaf_header_check(blk->bp, args->owner);
			if (fa) {
				__xfs_buf_mark_corrupt(blk->bp, fa);
				xfs_da_mark_sick(args);
				return -EFSCORRUPTED;
			}
			blk->magic = XFS_ATTR_LEAF_MAGIC;
			ASSERT(level == path->active-1);
			blk->index = 0;
@@ -2290,6 +2323,7 @@ xfs_da3_swap_lastblock(
	struct xfs_buf		*last_buf;
	struct xfs_buf		*sib_buf;
	struct xfs_buf		*par_buf;
	xfs_failaddr_t		fa;
	xfs_dahash_t		dead_hash;
	xfs_fileoff_t		lastoff;
	xfs_dablk_t		dead_blkno;
@@ -2326,6 +2360,14 @@ xfs_da3_swap_lastblock(
	error = xfs_da3_node_read(tp, dp, last_blkno, &last_buf, w);
	if (error)
		return error;
	fa = xfs_da3_header_check(last_buf, args->owner);
	if (fa) {
		__xfs_buf_mark_corrupt(last_buf, fa);
		xfs_trans_brelse(tp, last_buf);
		xfs_da_mark_sick(args);
		return -EFSCORRUPTED;
	}

	/*
	 * Copy the last block into the dead buffer and log it.
	 */
+1 −0
Original line number Diff line number Diff line
@@ -236,6 +236,7 @@ void xfs_da3_node_hdr_from_disk(struct xfs_mount *mp,
		struct xfs_da3_icnode_hdr *to, struct xfs_da_intnode *from);
void	xfs_da3_node_hdr_to_disk(struct xfs_mount *mp,
		struct xfs_da_intnode *to, struct xfs_da3_icnode_hdr *from);
xfs_failaddr_t xfs_da3_header_check(struct xfs_buf *bp, xfs_ino_t owner);

extern struct kmem_cache	*xfs_da_state_cache;

Loading