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

xfs: validate dabtree node buffer owners



Check the owner field of dabtree node blocks.

Signed-off-by: default avatarDarrick J. Wong <djwong@kernel.org>
Reviewed-by: default avatarChristoph Hellwig <hch@lst.de>
parent 8c25dc72
Loading
Loading
Loading
Loading
+109 −0
Original line number Diff line number Diff line
@@ -252,6 +252,26 @@ xfs_da3_node_verify(
	return NULL;
}

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

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

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

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

	return NULL;
}

xfs_failaddr_t
xfs_da3_header_check(
	struct xfs_buf		*bp,
@@ -266,6 +286,8 @@ xfs_da3_header_check(
	switch (hdr->magic) {
	case cpu_to_be16(XFS_ATTR3_LEAF_MAGIC):
		return xfs_attr3_leaf_header_check(bp, owner);
	case cpu_to_be16(XFS_DA3_NODE_MAGIC):
		return xfs_da3_node_header_check(bp, owner);
	}

	return NULL;
@@ -1218,6 +1240,7 @@ xfs_da3_root_join(
	struct xfs_da3_icnode_hdr oldroothdr;
	int			error;
	struct xfs_inode	*dp = state->args->dp;
	xfs_failaddr_t		fa;

	trace_xfs_da_root_join(state->args);

@@ -1244,6 +1267,13 @@ xfs_da3_root_join(
	error = xfs_da3_node_read(args->trans, dp, child, &bp, args->whichfork);
	if (error)
		return error;
	fa = xfs_da3_header_check(bp, args->owner);
	if (fa) {
		__xfs_buf_mark_corrupt(bp, fa);
		xfs_trans_brelse(args->trans, bp);
		xfs_da_mark_sick(args);
		return -EFSCORRUPTED;
	}
	xfs_da_blkinfo_onlychild_validate(bp->b_addr, oldroothdr.level);

	/*
@@ -1278,6 +1308,7 @@ xfs_da3_node_toosmall(
	struct xfs_da_blkinfo	*info;
	xfs_dablk_t		blkno;
	struct xfs_buf		*bp;
	xfs_failaddr_t		fa;
	struct xfs_da3_icnode_hdr nodehdr;
	int			count;
	int			forward;
@@ -1352,6 +1383,13 @@ xfs_da3_node_toosmall(
				state->args->whichfork);
		if (error)
			return error;
		fa = xfs_da3_node_header_check(bp, state->args->owner);
		if (fa) {
			__xfs_buf_mark_corrupt(bp, fa);
			xfs_trans_brelse(state->args->trans, bp);
			xfs_da_mark_sick(state->args);
			return -EFSCORRUPTED;
		}

		node = bp->b_addr;
		xfs_da3_node_hdr_from_disk(dp->i_mount, &thdr, node);
@@ -1674,6 +1712,13 @@ xfs_da3_node_lookup_int(
			return -EFSCORRUPTED;
		}

		fa = xfs_da3_node_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_DA_NODE_MAGIC;

		/*
@@ -1846,6 +1891,7 @@ xfs_da3_blk_link(
	struct xfs_da_blkinfo	*tmp_info;
	struct xfs_da_args	*args;
	struct xfs_buf		*bp;
	xfs_failaddr_t		fa;
	int			before = 0;
	int			error;
	struct xfs_inode	*dp = state->args->dp;
@@ -1889,6 +1935,13 @@ xfs_da3_blk_link(
						&bp, args->whichfork);
			if (error)
				return error;
			fa = xfs_da3_header_check(bp, args->owner);
			if (fa) {
				__xfs_buf_mark_corrupt(bp, fa);
				xfs_trans_brelse(args->trans, bp);
				xfs_da_mark_sick(args);
				return -EFSCORRUPTED;
			}
			ASSERT(bp != NULL);
			tmp_info = bp->b_addr;
			ASSERT(tmp_info->magic == old_info->magic);
@@ -1910,6 +1963,13 @@ xfs_da3_blk_link(
						&bp, args->whichfork);
			if (error)
				return error;
			fa = xfs_da3_header_check(bp, args->owner);
			if (fa) {
				__xfs_buf_mark_corrupt(bp, fa);
				xfs_trans_brelse(args->trans, bp);
				xfs_da_mark_sick(args);
				return -EFSCORRUPTED;
			}
			ASSERT(bp != NULL);
			tmp_info = bp->b_addr;
			ASSERT(tmp_info->magic == old_info->magic);
@@ -1939,6 +1999,7 @@ xfs_da3_blk_unlink(
	struct xfs_da_blkinfo	*tmp_info;
	struct xfs_da_args	*args;
	struct xfs_buf		*bp;
	xfs_failaddr_t		fa;
	int			error;

	/*
@@ -1969,6 +2030,13 @@ xfs_da3_blk_unlink(
						&bp, args->whichfork);
			if (error)
				return error;
			fa = xfs_da3_header_check(bp, args->owner);
			if (fa) {
				__xfs_buf_mark_corrupt(bp, fa);
				xfs_trans_brelse(args->trans, bp);
				xfs_da_mark_sick(args);
				return -EFSCORRUPTED;
			}
			ASSERT(bp != NULL);
			tmp_info = bp->b_addr;
			ASSERT(tmp_info->magic == save_info->magic);
@@ -1986,6 +2054,13 @@ xfs_da3_blk_unlink(
						&bp, args->whichfork);
			if (error)
				return error;
			fa = xfs_da3_header_check(bp, args->owner);
			if (fa) {
				__xfs_buf_mark_corrupt(bp, fa);
				xfs_trans_brelse(args->trans, bp);
				xfs_da_mark_sick(args);
				return -EFSCORRUPTED;
			}
			ASSERT(bp != NULL);
			tmp_info = bp->b_addr;
			ASSERT(tmp_info->magic == save_info->magic);
@@ -2101,6 +2176,12 @@ xfs_da3_path_shift(
		switch (be16_to_cpu(info->magic)) {
		case XFS_DA_NODE_MAGIC:
		case XFS_DA3_NODE_MAGIC:
			fa = xfs_da3_node_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_DA_NODE_MAGIC;
			xfs_da3_node_hdr_from_disk(dp->i_mount, &nodehdr,
						   bp->b_addr);
@@ -2406,6 +2487,13 @@ xfs_da3_swap_lastblock(
		error = xfs_da3_node_read(tp, dp, sib_blkno, &sib_buf, w);
		if (error)
			goto done;
		fa = xfs_da3_header_check(sib_buf, args->owner);
		if (fa) {
			__xfs_buf_mark_corrupt(sib_buf, fa);
			xfs_da_mark_sick(args);
			error = -EFSCORRUPTED;
			goto done;
		}
		sib_info = sib_buf->b_addr;
		if (XFS_IS_CORRUPT(mp,
				   be32_to_cpu(sib_info->forw) != last_blkno ||
@@ -2427,6 +2515,13 @@ xfs_da3_swap_lastblock(
		error = xfs_da3_node_read(tp, dp, sib_blkno, &sib_buf, w);
		if (error)
			goto done;
		fa = xfs_da3_header_check(sib_buf, args->owner);
		if (fa) {
			__xfs_buf_mark_corrupt(sib_buf, fa);
			xfs_da_mark_sick(args);
			error = -EFSCORRUPTED;
			goto done;
		}
		sib_info = sib_buf->b_addr;
		if (XFS_IS_CORRUPT(mp,
				   be32_to_cpu(sib_info->back) != last_blkno ||
@@ -2450,6 +2545,13 @@ xfs_da3_swap_lastblock(
		error = xfs_da3_node_read(tp, dp, par_blkno, &par_buf, w);
		if (error)
			goto done;
		fa = xfs_da3_node_header_check(par_buf, args->owner);
		if (fa) {
			__xfs_buf_mark_corrupt(par_buf, fa);
			xfs_da_mark_sick(args);
			error = -EFSCORRUPTED;
			goto done;
		}
		par_node = par_buf->b_addr;
		xfs_da3_node_hdr_from_disk(dp->i_mount, &par_hdr, par_node);
		if (XFS_IS_CORRUPT(mp,
@@ -2499,6 +2601,13 @@ xfs_da3_swap_lastblock(
		error = xfs_da3_node_read(tp, dp, par_blkno, &par_buf, w);
		if (error)
			goto done;
		fa = xfs_da3_node_header_check(par_buf, args->owner);
		if (fa) {
			__xfs_buf_mark_corrupt(par_buf, fa);
			xfs_da_mark_sick(args);
			error = -EFSCORRUPTED;
			goto done;
		}
		par_node = par_buf->b_addr;
		xfs_da3_node_hdr_from_disk(dp->i_mount, &par_hdr, par_node);
		if (XFS_IS_CORRUPT(mp, par_hdr.level != level)) {
+1 −0
Original line number Diff line number Diff line
@@ -237,6 +237,7 @@ void xfs_da3_node_hdr_from_disk(struct xfs_mount *mp,
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);
xfs_failaddr_t xfs_da3_node_header_check(struct xfs_buf *bp, xfs_ino_t owner);

extern struct kmem_cache	*xfs_da_state_cache;

+9 −0
Original line number Diff line number Diff line
@@ -239,6 +239,10 @@ xfs_attr_node_list_lookup(
			goto out_corruptbuf;
		}

		fa = xfs_da3_node_header_check(bp, dp->i_ino);
		if (fa)
			goto out_corruptbuf;

		xfs_da3_node_hdr_from_disk(mp, &nodehdr, node);

		/* Tree taller than we can handle; bail out! */
@@ -335,6 +339,11 @@ xfs_attr_node_list(
		case XFS_DA_NODE_MAGIC:
		case XFS_DA3_NODE_MAGIC:
			trace_xfs_attr_list_wrong_blk(context);
			fa = xfs_da3_node_header_check(bp, dp->i_ino);
			if (fa) {
				__xfs_buf_mark_corrupt(bp, fa);
				xfs_dirattr_mark_sick(dp, XFS_ATTR_FORK);
			}
			xfs_trans_brelse(context->tp, bp);
			bp = NULL;
			break;