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

xfs: validate explicit directory data buffer owners



Port the existing directory data header checking function to accept an
owner number instead of an xfs_inode, then update the callsites to use
xfs_da_args.owner when possible.

Signed-off-by: default avatarDarrick J. Wong <djwong@kernel.org>
Reviewed-by: default avatarChristoph Hellwig <hch@lst.de>
parent 402eef10
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -102,6 +102,7 @@ extern struct xfs_dir2_data_free *xfs_dir2_data_freefind(
extern int xfs_dir_ino_validate(struct xfs_mount *mp, xfs_ino_t ino);

xfs_failaddr_t xfs_dir3_leaf_header_check(struct xfs_buf *bp, xfs_ino_t owner);
xfs_failaddr_t xfs_dir3_data_header_check(struct xfs_buf *bp, xfs_ino_t owner);

extern const struct xfs_buf_ops xfs_dir3_block_buf_ops;
extern const struct xfs_buf_ops xfs_dir3_leafn_buf_ops;
+2 −1
Original line number Diff line number Diff line
@@ -982,7 +982,8 @@ xfs_dir2_leaf_to_block(
	 * Read the data block if we don't already have it, give up if it fails.
	 */
	if (!dbp) {
		error = xfs_dir3_data_read(tp, dp, args->geo->datablk, 0, &dbp);
		error = xfs_dir3_data_read(tp, dp, args->owner,
				args->geo->datablk, 0, &dbp);
		if (error)
			return error;
	}
+10 −6
Original line number Diff line number Diff line
@@ -395,17 +395,20 @@ static const struct xfs_buf_ops xfs_dir3_data_reada_buf_ops = {
	.verify_write = xfs_dir3_data_write_verify,
};

static xfs_failaddr_t
xfs_failaddr_t
xfs_dir3_data_header_check(
	struct xfs_inode	*dp,
	struct xfs_buf		*bp)
	struct xfs_buf		*bp,
	xfs_ino_t		owner)
{
	struct xfs_mount	*mp = dp->i_mount;
	struct xfs_mount	*mp = bp->b_mount;

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

		if (be64_to_cpu(hdr3->hdr.owner) != dp->i_ino)
		if (hdr3->hdr.magic != cpu_to_be32(XFS_DIR3_DATA_MAGIC))
			return __this_address;

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

@@ -416,6 +419,7 @@ int
xfs_dir3_data_read(
	struct xfs_trans	*tp,
	struct xfs_inode	*dp,
	xfs_ino_t		owner,
	xfs_dablk_t		bno,
	unsigned int		flags,
	struct xfs_buf		**bpp)
@@ -429,7 +433,7 @@ xfs_dir3_data_read(
		return err;

	/* Check things that we can't do in the verifier. */
	fa = xfs_dir3_data_header_check(dp, *bpp);
	fa = xfs_dir3_data_header_check(*bpp, owner);
	if (fa) {
		__xfs_buf_mark_corrupt(*bpp, fa);
		xfs_trans_brelse(tp, *bpp);
+11 −10
Original line number Diff line number Diff line
@@ -885,9 +885,9 @@ xfs_dir2_leaf_addname(
		 * Already had space in some data block.
		 * Just read that one in.
		 */
		error = xfs_dir3_data_read(tp, dp,
				   xfs_dir2_db_to_da(args->geo, use_block),
				   0, &dbp);
		error = xfs_dir3_data_read(tp, dp, args->owner,
				xfs_dir2_db_to_da(args->geo, use_block), 0,
				&dbp);
		if (error) {
			xfs_trans_brelse(tp, lbp);
			return error;
@@ -1328,9 +1328,9 @@ xfs_dir2_leaf_lookup_int(
		if (newdb != curdb) {
			if (dbp)
				xfs_trans_brelse(tp, dbp);
			error = xfs_dir3_data_read(tp, dp,
					   xfs_dir2_db_to_da(args->geo, newdb),
					   0, &dbp);
			error = xfs_dir3_data_read(tp, dp, args->owner,
					xfs_dir2_db_to_da(args->geo, newdb), 0,
					&dbp);
			if (error) {
				xfs_trans_brelse(tp, lbp);
				return error;
@@ -1370,9 +1370,9 @@ xfs_dir2_leaf_lookup_int(
		ASSERT(cidb != -1);
		if (cidb != curdb) {
			xfs_trans_brelse(tp, dbp);
			error = xfs_dir3_data_read(tp, dp,
					   xfs_dir2_db_to_da(args->geo, cidb),
					   0, &dbp);
			error = xfs_dir3_data_read(tp, dp, args->owner,
					xfs_dir2_db_to_da(args->geo, cidb), 0,
					&dbp);
			if (error) {
				xfs_trans_brelse(tp, lbp);
				return error;
@@ -1666,7 +1666,8 @@ xfs_dir2_leaf_trim_data(
	/*
	 * Read the offending data block.  We need its buffer.
	 */
	error = xfs_dir3_data_read(tp, dp, xfs_dir2_db_to_da(geo, db), 0, &dbp);
	error = xfs_dir3_data_read(tp, dp, args->owner,
			xfs_dir2_db_to_da(geo, db), 0, &dbp);
	if (error)
		return error;

+3 −4
Original line number Diff line number Diff line
@@ -863,7 +863,7 @@ xfs_dir2_leafn_lookup_for_entry(
				ASSERT(state->extravalid);
				curbp = state->extrablk.bp;
			} else {
				error = xfs_dir3_data_read(tp, dp,
				error = xfs_dir3_data_read(tp, dp, args->owner,
						xfs_dir2_db_to_da(args->geo,
								  newdb),
						0, &curbp);
@@ -1949,9 +1949,8 @@ xfs_dir2_node_addname_int(
						  &freehdr, &findex);
	} else {
		/* Read the data block in. */
		error = xfs_dir3_data_read(tp, dp,
					   xfs_dir2_db_to_da(args->geo, dbno),
					   0, &dbp);
		error = xfs_dir3_data_read(tp, dp, args->owner,
				xfs_dir2_db_to_da(args->geo, dbno), 0, &dbp);
	}
	if (error)
		return error;
Loading