Commit 402eef10 authored by Darrick J. Wong's avatar Darrick J. Wong

xfs: validate directory leaf buffer owners

Check the owner field of directory leaf blocks.
Signed-off-by: default avatarDarrick J. Wong <djwong@kernel.org>
Reviewed-by: default avatarChristoph Hellwig <hch@lst.de>
parent d44bea9b
......@@ -288,8 +288,12 @@ xfs_da3_header_check(
return xfs_attr3_leaf_header_check(bp, owner);
case cpu_to_be16(XFS_DA3_NODE_MAGIC):
return xfs_da3_node_header_check(bp, owner);
case cpu_to_be16(XFS_DIR3_LEAF1_MAGIC):
case cpu_to_be16(XFS_DIR3_LEAFN_MAGIC):
return xfs_dir3_leaf_header_check(bp, owner);
}
ASSERT(0);
return NULL;
}
......@@ -1700,6 +1704,12 @@ xfs_da3_node_lookup_int(
if (magic == XFS_DIR2_LEAFN_MAGIC ||
magic == XFS_DIR3_LEAFN_MAGIC) {
fa = xfs_dir3_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_DIR2_LEAFN_MAGIC;
blk->hashval = xfs_dir2_leaf_lasthash(args->dp,
blk->bp, NULL);
......@@ -2208,6 +2218,12 @@ xfs_da3_path_shift(
break;
case XFS_DIR2_LEAFN_MAGIC:
case XFS_DIR3_LEAFN_MAGIC:
fa = xfs_dir3_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_DIR2_LEAFN_MAGIC;
ASSERT(level == path->active-1);
blk->index = 0;
......
......@@ -101,6 +101,8 @@ 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);
extern const struct xfs_buf_ops xfs_dir3_block_buf_ops;
extern const struct xfs_buf_ops xfs_dir3_leafn_buf_ops;
extern const struct xfs_buf_ops xfs_dir3_leaf1_buf_ops;
......
......@@ -208,6 +208,29 @@ xfs_dir3_leaf_verify(
return xfs_dir3_leaf_check_int(mp, &leafhdr, bp->b_addr, true);
}
xfs_failaddr_t
xfs_dir3_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_dir3_leaf *hdr3 = bp->b_addr;
if (hdr3->hdr.info.hdr.magic !=
cpu_to_be16(XFS_DIR3_LEAF1_MAGIC) &&
hdr3->hdr.info.hdr.magic !=
cpu_to_be16(XFS_DIR3_LEAFN_MAGIC))
return __this_address;
if (be64_to_cpu(hdr3->hdr.info.owner) != owner)
return __this_address;
}
return NULL;
}
static void
xfs_dir3_leaf_read_verify(
struct xfs_buf *bp)
......@@ -271,32 +294,60 @@ int
xfs_dir3_leaf_read(
struct xfs_trans *tp,
struct xfs_inode *dp,
xfs_ino_t owner,
xfs_dablk_t fbno,
struct xfs_buf **bpp)
{
xfs_failaddr_t fa;
int err;
err = xfs_da_read_buf(tp, dp, fbno, 0, bpp, XFS_DATA_FORK,
&xfs_dir3_leaf1_buf_ops);
if (!err && tp && *bpp)
if (err || !(*bpp))
return err;
fa = xfs_dir3_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_DATA_FORK);
return -EFSCORRUPTED;
}
if (tp)
xfs_trans_buf_set_type(tp, *bpp, XFS_BLFT_DIR_LEAF1_BUF);
return err;
return 0;
}
int
xfs_dir3_leafn_read(
struct xfs_trans *tp,
struct xfs_inode *dp,
xfs_ino_t owner,
xfs_dablk_t fbno,
struct xfs_buf **bpp)
{
xfs_failaddr_t fa;
int err;
err = xfs_da_read_buf(tp, dp, fbno, 0, bpp, XFS_DATA_FORK,
&xfs_dir3_leafn_buf_ops);
if (!err && tp && *bpp)
if (err || !(*bpp))
return err;
fa = xfs_dir3_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_DATA_FORK);
return -EFSCORRUPTED;
}
if (tp)
xfs_trans_buf_set_type(tp, *bpp, XFS_BLFT_DIR_LEAFN_BUF);
return err;
return 0;
}
/*
......@@ -646,7 +697,8 @@ xfs_dir2_leaf_addname(
trace_xfs_dir2_leaf_addname(args);
error = xfs_dir3_leaf_read(tp, dp, args->geo->leafblk, &lbp);
error = xfs_dir3_leaf_read(tp, dp, args->owner, args->geo->leafblk,
&lbp);
if (error)
return error;
......@@ -1237,7 +1289,8 @@ xfs_dir2_leaf_lookup_int(
tp = args->trans;
mp = dp->i_mount;
error = xfs_dir3_leaf_read(tp, dp, args->geo->leafblk, &lbp);
error = xfs_dir3_leaf_read(tp, dp, args->owner, args->geo->leafblk,
&lbp);
if (error)
return error;
......
......@@ -1562,7 +1562,8 @@ xfs_dir2_leafn_toosmall(
/*
* Read the sibling leaf block.
*/
error = xfs_dir3_leafn_read(state->args->trans, dp, blkno, &bp);
error = xfs_dir3_leafn_read(state->args->trans, dp,
state->args->owner, blkno, &bp);
if (error)
return error;
......
......@@ -95,9 +95,9 @@ void xfs_dir2_leaf_hdr_from_disk(struct xfs_mount *mp,
void xfs_dir2_leaf_hdr_to_disk(struct xfs_mount *mp, struct xfs_dir2_leaf *to,
struct xfs_dir3_icleaf_hdr *from);
int xfs_dir3_leaf_read(struct xfs_trans *tp, struct xfs_inode *dp,
xfs_dablk_t fbno, struct xfs_buf **bpp);
xfs_ino_t owner, xfs_dablk_t fbno, struct xfs_buf **bpp);
int xfs_dir3_leafn_read(struct xfs_trans *tp, struct xfs_inode *dp,
xfs_dablk_t fbno, struct xfs_buf **bpp);
xfs_ino_t owner, xfs_dablk_t fbno, struct xfs_buf **bpp);
extern int xfs_dir2_block_to_leaf(struct xfs_da_args *args,
struct xfs_buf *dbp);
extern int xfs_dir2_leaf_addname(struct xfs_da_args *args);
......
......@@ -470,7 +470,7 @@ xchk_directory_leaf1_bestfree(
int error;
/* Read the free space block. */
error = xfs_dir3_leaf_read(sc->tp, sc->ip, lblk, &bp);
error = xfs_dir3_leaf_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);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment