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

xfs: validate explicit directory free block owners



Port the existing directory freespace block 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 29b41ce9
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -1806,7 +1806,8 @@ xfs_dir2_node_to_leaf(
	/*
	 * Read the freespace block.
	 */
	error = xfs_dir2_free_read(tp, dp,  args->geo->freeblk, &fbp);
	error = xfs_dir2_free_read(tp, dp, args->owner, args->geo->freeblk,
			&fbp);
	if (error)
		return error;
	xfs_dir2_free_hdr_from_disk(mp, &freehdr, fbp->b_addr);
+18 −14
Original line number Diff line number Diff line
@@ -175,11 +175,11 @@ const struct xfs_buf_ops xfs_dir3_free_buf_ops = {
/* Everything ok in the free block header? */
static xfs_failaddr_t
xfs_dir3_free_header_check(
	struct xfs_inode	*dp,
	xfs_dablk_t		fbno,
	struct xfs_buf		*bp)
	struct xfs_buf		*bp,
	xfs_ino_t		owner,
	xfs_dablk_t		fbno)
{
	struct xfs_mount	*mp = dp->i_mount;
	struct xfs_mount	*mp = bp->b_mount;
	int			maxbests = mp->m_dir_geo->free_max_bests;
	unsigned int		firstdb;

@@ -195,7 +195,7 @@ xfs_dir3_free_header_check(
			return __this_address;
		if (be32_to_cpu(hdr3->nvalid) < be32_to_cpu(hdr3->nused))
			return __this_address;
		if (be64_to_cpu(hdr3->hdr.owner) != dp->i_ino)
		if (be64_to_cpu(hdr3->hdr.owner) != owner)
			return __this_address;
	} else {
		struct xfs_dir2_free_hdr *hdr = bp->b_addr;
@@ -214,6 +214,7 @@ static int
__xfs_dir3_free_read(
	struct xfs_trans	*tp,
	struct xfs_inode	*dp,
	xfs_ino_t		owner,
	xfs_dablk_t		fbno,
	unsigned int		flags,
	struct xfs_buf		**bpp)
@@ -227,7 +228,7 @@ __xfs_dir3_free_read(
		return err;

	/* Check things that we can't do in the verifier. */
	fa = xfs_dir3_free_header_check(dp, fbno, *bpp);
	fa = xfs_dir3_free_header_check(*bpp, owner, fbno);
	if (fa) {
		__xfs_buf_mark_corrupt(*bpp, fa);
		xfs_trans_brelse(tp, *bpp);
@@ -299,20 +300,23 @@ int
xfs_dir2_free_read(
	struct xfs_trans	*tp,
	struct xfs_inode	*dp,
	xfs_ino_t		owner,
	xfs_dablk_t		fbno,
	struct xfs_buf		**bpp)
{
	return __xfs_dir3_free_read(tp, dp, fbno, 0, bpp);
	return __xfs_dir3_free_read(tp, dp, owner, fbno, 0, bpp);
}

static int
xfs_dir2_free_try_read(
	struct xfs_trans	*tp,
	struct xfs_inode	*dp,
	xfs_ino_t		owner,
	xfs_dablk_t		fbno,
	struct xfs_buf		**bpp)
{
	return __xfs_dir3_free_read(tp, dp, fbno, XFS_DABUF_MAP_HOLE_OK, bpp);
	return __xfs_dir3_free_read(tp, dp, owner, fbno, XFS_DABUF_MAP_HOLE_OK,
			bpp);
}

static int
@@ -717,7 +721,7 @@ xfs_dir2_leafn_lookup_for_addname(
				if (curbp)
					xfs_trans_brelse(tp, curbp);

				error = xfs_dir2_free_read(tp, dp,
				error = xfs_dir2_free_read(tp, dp, args->owner,
						xfs_dir2_db_to_da(args->geo,
								  newfdb),
						&curbp);
@@ -1356,8 +1360,8 @@ xfs_dir2_leafn_remove(
		 * read in the free block.
		 */
		fdb = xfs_dir2_db_to_fdb(geo, db);
		error = xfs_dir2_free_read(tp, dp, xfs_dir2_db_to_da(geo, fdb),
					   &fbp);
		error = xfs_dir2_free_read(tp, dp, args->owner,
				xfs_dir2_db_to_da(geo, fdb), &fbp);
		if (error)
			return error;
		free = fbp->b_addr;
@@ -1716,7 +1720,7 @@ xfs_dir2_node_add_datablk(
	 * that was just allocated.
	 */
	fbno = xfs_dir2_db_to_fdb(args->geo, *dbno);
	error = xfs_dir2_free_try_read(tp, dp,
	error = xfs_dir2_free_try_read(tp, dp, args->owner,
			       xfs_dir2_db_to_da(args->geo, fbno), &fbp);
	if (error)
		return error;
@@ -1863,7 +1867,7 @@ xfs_dir2_node_find_freeblk(
		 * so this might not succeed.  This should be really rare, so
		 * there's no reason to avoid it.
		 */
		error = xfs_dir2_free_try_read(tp, dp,
		error = xfs_dir2_free_try_read(tp, dp, args->owner,
				xfs_dir2_db_to_da(args->geo, fbno),
				&fbp);
		if (error)
@@ -2302,7 +2306,7 @@ xfs_dir2_node_trim_free(
	/*
	 * Read the freespace block.
	 */
	error = xfs_dir2_free_try_read(tp, dp, fo, &bp);
	error = xfs_dir2_free_try_read(tp, dp, args->owner, fo, &bp);
	if (error)
		return error;
	/*
+2 −2
Original line number Diff line number Diff line
@@ -155,8 +155,8 @@ extern int xfs_dir2_node_removename(struct xfs_da_args *args);
extern int xfs_dir2_node_replace(struct xfs_da_args *args);
extern int xfs_dir2_node_trim_free(struct xfs_da_args *args, xfs_fileoff_t fo,
		int *rvalp);
extern int xfs_dir2_free_read(struct xfs_trans *tp, struct xfs_inode *dp,
		xfs_dablk_t fbno, struct xfs_buf **bpp);
int xfs_dir2_free_read(struct xfs_trans *tp, struct xfs_inode *dp,
		xfs_ino_t owner, xfs_dablk_t fbno, struct xfs_buf **bpp);

/* xfs_dir2_sf.c */
xfs_ino_t xfs_dir2_sf_get_ino(struct xfs_mount *mp, struct xfs_dir2_sf_hdr *hdr,
+1 −1
Original line number Diff line number Diff line
@@ -577,7 +577,7 @@ xchk_directory_free_bestfree(
	int				error;

	/* Read the free space block */
	error = xfs_dir2_free_read(sc->tp, sc->ip, lblk, &bp);
	error = xfs_dir2_free_read(sc->tp, sc->ip, sc->ip->i_ino, lblk, &bp);
	if (!xchk_fblock_process_error(sc, XFS_DATA_FORK, lblk, &error))
		return error;
	xchk_buffer_recheck(sc, bp);